class CommentBase
Base class for comment objects that provides common functionality for ReviewComment and ApprovalComment types, managing comment data, metadata, and lifecycle operations.
/tf/active/vicechatdev/CDocs single class/models/workflow_base.py
531 - 716
moderate
Purpose
CommentBase serves as an abstract base class for different comment types in a document review/approval system. It handles common comment properties like text, author information, timestamps, resolution status, location/page references, and threading (replies). The class uses a dictionary-based internal storage (_data) with property accessors, tracks modifications, and provides methods for resolving/unresolving comments and managing comment threads. Subclasses must implement the save() method for persistence.
Source Code
class CommentBase:
"""Base class for comments (ReviewComment and ApprovalComment)."""
def __init__(self, data=None):
"""Initialize with optional data dictionary."""
self._data = data or {}
self._modified = False
# Set default values if not provided
if 'UID' not in self._data:
self._data['UID'] = str(uuid.uuid4())
self._modified = True
if 'created_at' not in self._data:
self._data['created_at'] = datetime.now().isoformat()
self._data['updated_at'] = self._data['created_at']
self._modified = True
@property
def uid(self) -> str:
"""Get the UID."""
return self._data.get('UID', '')
@property
def text(self) -> str:
"""Get the comment text."""
return self._data.get('text', '')
@text.setter
def text(self, value: str) -> None:
"""Set the comment text."""
self._data['text'] = value
self._data['updated_at'] = datetime.now().isoformat()
self._modified = True
@property
def comment_type(self) -> str:
"""Get the comment type."""
return self._data.get('comment_type', CommentType.GENERAL)
@comment_type.setter
def comment_type(self, value: str) -> None:
"""Set the comment type."""
self._data['comment_type'] = value
self._modified = True
@property
def context(self) -> Dict[str, Any]:
"""Get the context information."""
return self._data.get('context', {})
@context.setter
def context(self, value: Dict[str, Any]) -> None:
"""Set the context information."""
self._data['context'] = value
self._modified = True
@property
def created_at(self) -> str:
"""Get the creation timestamp."""
return self._data.get('created_at', '')
@property
def updated_at(self) -> str:
"""Get the update timestamp."""
return self._data.get('updated_at', self.created_at)
@property
def resolved(self) -> bool:
"""Check if the comment is resolved."""
return self._data.get('resolved', False)
@resolved.setter
def resolved(self, value: bool) -> None:
"""Set whether the comment is resolved."""
self._data['resolved'] = value
self._modified = True
@property
def author_uid(self) -> str:
"""Get the UID of the comment author."""
return self._data.get('author_uid', '')
@author_uid.setter
def author_uid(self, value: str) -> None:
"""Set the UID of the comment author."""
self._data['author_uid'] = value
self._modified = True
@property
def author_name(self) -> str:
"""Get the name of the comment author."""
return self._data.get('author_name', '')
@author_name.setter
def author_name(self, value: str) -> None:
"""Set the name of the comment author."""
self._data['author_name'] = value
self._modified = True
@property
def page(self) -> Optional[int]:
"""Get the page number this comment refers to."""
return self._data.get('page')
@page.setter
def page(self, value: Optional[int]) -> None:
"""Set the page number this comment refers to."""
self._data['page'] = value
self._modified = True
@property
def location(self) -> Dict[str, Any]:
"""Get the location information (e.g., text selection coordinates)."""
return self._data.get('location', {})
@location.setter
def location(self, value: Dict[str, Any]) -> None:
"""Set the location information."""
self._data['location'] = value
self._modified = True
@property
def parent_comment_uid(self) -> Optional[str]:
"""Get the UID of the parent comment if this is a reply."""
return self._data.get('parent_comment_uid')
@parent_comment_uid.setter
def parent_comment_uid(self, value: Optional[str]) -> None:
"""Set the UID of the parent comment."""
self._data['parent_comment_uid'] = value
self._modified = True
def get_author(self):
"""Get the user object for the comment author."""
from CDocs.models.user_extensions import DocUser
if not self.author_uid:
return None
return DocUser.get_by_uid(self.author_uid)
def get_replies(self) -> List['CommentBase']:
"""Get replies to this comment. Implemented in subclasses."""
return []
def is_reply(self) -> bool:
"""Check if this comment is a reply to another comment."""
return self.parent_comment_uid is not None
def notify_mentioned_users(self) -> bool:
"""Notify users mentioned in comment. Implemented in subclasses."""
return False
def resolve(self, resolution_text: Optional[str] = None) -> bool:
"""Mark the comment as resolved, optionally with resolution text."""
self.resolved = True
if resolution_text:
if 'context' not in self._data:
self._data['context'] = {}
if 'resolution' not in self._data['context']:
self._data['context']['resolution'] = {}
self._data['context']['resolution']['text'] = resolution_text
self._data['context']['resolution']['resolved_at'] = datetime.now().isoformat()
self._data['updated_at'] = datetime.now().isoformat()
self._modified = True
return self.save()
def unresolve(self) -> bool:
"""Mark the comment as unresolved."""
self.resolved = False
if 'context' in self._data and 'resolution' in self._data['context']:
del self._data['context']['resolution']
self._data['updated_at'] = datetime.now().isoformat()
self._modified = True
return self.save()
def save(self) -> bool:
"""Save changes to database."""
# To be implemented in subclasses
raise NotImplementedError("Subclasses must implement save method")
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
bases |
- | - |
Parameter Details
data: Optional dictionary containing initial comment data. If None, an empty dictionary is created. The dictionary can contain keys like 'UID', 'text', 'comment_type', 'author_uid', 'author_name', 'page', 'location', 'context', 'resolved', 'parent_comment_uid', 'created_at', 'updated_at'. If 'UID' is not provided, a new UUID is generated. If 'created_at' is not provided, current timestamp is set.
Return Value
Instantiation returns a CommentBase object (or subclass instance) with initialized internal state. Key method returns: uid (str), text (str), comment_type (str), context (Dict), created_at (str), updated_at (str), resolved (bool), author_uid (str), author_name (str), page (Optional[int]), location (Dict), parent_comment_uid (Optional[str]), get_author() returns DocUser or None, get_replies() returns List of CommentBase objects, is_reply() returns bool, notify_mentioned_users() returns bool, resolve() returns bool, unresolve() returns bool, save() raises NotImplementedError.
Class Interface
Methods
__init__(self, data: Optional[Dict[str, Any]] = None) -> None
Purpose: Initialize comment with optional data dictionary, setting defaults for UID and timestamps if not provided
Parameters:
data: Optional dictionary containing initial comment data with keys like UID, text, author_uid, etc.
Returns: None
@property uid(self) -> str
property
Purpose: Get the unique identifier for this comment
Returns: String UUID of the comment, empty string if not set
@property text(self) -> str
property
Purpose: Get the comment text content
Returns: String containing the comment text, empty string if not set
@text.setter text(self, value: str) -> None
property
Purpose: Set the comment text and update the updated_at timestamp
Parameters:
value: String containing the new comment text
Returns: None
@property comment_type(self) -> str
property
Purpose: Get the type/category of this comment
Returns: String representing comment type, defaults to CommentType.GENERAL if not set
@comment_type.setter comment_type(self, value: str) -> None
property
Purpose: Set the comment type/category
Parameters:
value: String representing the comment type
Returns: None
@property context(self) -> Dict[str, Any]
property
Purpose: Get additional context information stored with the comment
Returns: Dictionary containing context data, empty dict if not set
@context.setter context(self, value: Dict[str, Any]) -> None
property
Purpose: Set additional context information for the comment
Parameters:
value: Dictionary containing context data
Returns: None
@property created_at(self) -> str
property
Purpose: Get the timestamp when the comment was created
Returns: ISO format timestamp string, empty string if not set
@property updated_at(self) -> str
property
Purpose: Get the timestamp when the comment was last updated
Returns: ISO format timestamp string, falls back to created_at if not set
@property resolved(self) -> bool
property
Purpose: Check if the comment has been marked as resolved
Returns: Boolean indicating resolution status, False if not set
@resolved.setter resolved(self, value: bool) -> None
property
Purpose: Set whether the comment is resolved
Parameters:
value: Boolean indicating if comment should be marked resolved
Returns: None
@property author_uid(self) -> str
property
Purpose: Get the unique identifier of the comment author
Returns: String UID of the author, empty string if not set
@author_uid.setter author_uid(self, value: str) -> None
property
Purpose: Set the unique identifier of the comment author
Parameters:
value: String UID of the author
Returns: None
@property author_name(self) -> str
property
Purpose: Get the display name of the comment author
Returns: String name of the author, empty string if not set
@author_name.setter author_name(self, value: str) -> None
property
Purpose: Set the display name of the comment author
Parameters:
value: String name of the author
Returns: None
@property page(self) -> Optional[int]
property
Purpose: Get the page number this comment refers to in the document
Returns: Integer page number or None if not set
@page.setter page(self, value: Optional[int]) -> None
property
Purpose: Set the page number this comment refers to
Parameters:
value: Integer page number or None
Returns: None
@property location(self) -> Dict[str, Any]
property
Purpose: Get spatial location information like text selection coordinates
Returns: Dictionary containing location data (e.g., x, y, width, height), empty dict if not set
@location.setter location(self, value: Dict[str, Any]) -> None
property
Purpose: Set spatial location information for the comment
Parameters:
value: Dictionary containing location data
Returns: None
@property parent_comment_uid(self) -> Optional[str]
property
Purpose: Get the UID of the parent comment if this is a reply
Returns: String UID of parent comment or None if this is a top-level comment
@parent_comment_uid.setter parent_comment_uid(self, value: Optional[str]) -> None
property
Purpose: Set the UID of the parent comment to create a reply relationship
Parameters:
value: String UID of parent comment or None
Returns: None
get_author(self) -> Optional[DocUser]
Purpose: Retrieve the DocUser object for the comment author from the database
Returns: DocUser object if author_uid is set and user exists, None otherwise
get_replies(self) -> List['CommentBase']
Purpose: Get all reply comments to this comment (must be implemented in subclasses)
Returns: List of CommentBase objects that are replies, empty list in base class
is_reply(self) -> bool
Purpose: Check if this comment is a reply to another comment
Returns: Boolean True if parent_comment_uid is set, False otherwise
notify_mentioned_users(self) -> bool
Purpose: Send notifications to users mentioned in the comment (must be implemented in subclasses)
Returns: Boolean indicating success, False in base class
resolve(self, resolution_text: Optional[str] = None) -> bool
Purpose: Mark the comment as resolved with optional resolution text and timestamp
Parameters:
resolution_text: Optional string describing the resolution
Returns: Boolean indicating if save was successful
unresolve(self) -> bool
Purpose: Mark the comment as unresolved and remove resolution metadata
Returns: Boolean indicating if save was successful
save(self) -> bool
Purpose: Persist comment changes to database (must be implemented in subclasses)
Returns: Boolean indicating save success
Attributes
| Name | Type | Description | Scope |
|---|---|---|---|
_data |
Dict[str, Any] | Internal dictionary storing all comment data including UID, text, timestamps, author info, location, context, and resolution status | instance |
_modified |
bool | Flag tracking whether the comment has been modified since last save, set to True by property setters | instance |
Dependencies
typingdatetimeuuidloggingCDocs.db.db_operationsCDocs.db.schema_managerCDocs.configCDocs.models.user_extensionsCDocs.models.document
Required Imports
from typing import List, Optional, Dict, Any, Union, Type
from datetime import datetime
import uuid
import logging
Conditional/Optional Imports
These imports are only needed under specific conditions:
from CDocs.models.user_extensions import DocUser
Condition: only when calling get_author() method to retrieve user objects
Required (conditional)from CDocs.db import db_operations as db
Condition: required by subclasses for database operations
Optionalfrom CDocs.db.schema_manager import NodeLabels, RelTypes
Condition: required by subclasses for database schema definitions
Optionalfrom CDocs.config import settings
Condition: required by subclasses for configuration access
Optionalfrom CDocs.models.document import DocumentVersion
Condition: required by subclasses for document version operations
OptionalUsage Example
# Note: CommentBase is abstract, typically used via subclasses
# Example showing typical usage pattern:
from datetime import datetime
import uuid
# Subclass implementation example
class ReviewComment(CommentBase):
def save(self):
# Implement actual save logic
return True
# Create new comment
comment = ReviewComment()
comment.text = "This section needs clarification"
comment.author_uid = "user-123"
comment.author_name = "John Doe"
comment.comment_type = "REVIEW"
comment.page = 5
comment.location = {"x": 100, "y": 200, "width": 150, "height": 20}
comment.save()
# Create reply to existing comment
reply = ReviewComment()
reply.text = "I agree, let me update this"
reply.author_uid = "user-456"
reply.author_name = "Jane Smith"
reply.parent_comment_uid = comment.uid
reply.save()
# Check if comment is a reply
if reply.is_reply():
print(f"This is a reply to {reply.parent_comment_uid}")
# Resolve comment
comment.resolve(resolution_text="Updated as requested")
# Access comment properties
print(f"Comment UID: {comment.uid}")
print(f"Created: {comment.created_at}")
print(f"Updated: {comment.updated_at}")
print(f"Resolved: {comment.resolved}")
# Get author information
author = comment.get_author()
if author:
print(f"Author: {author.name}")
# Unresolve if needed
comment.unresolve()
Best Practices
- This is an abstract base class - always use through subclasses that implement the save() method
- The _modified flag tracks changes but persistence depends on calling save() method
- All property setters automatically update the 'updated_at' timestamp and set _modified=True
- UID is auto-generated if not provided during initialization using uuid.uuid4()
- Timestamps are stored as ISO format strings (datetime.now().isoformat())
- The context property is a flexible dictionary for storing additional metadata
- Resolution information is stored in context['resolution'] with text and timestamp
- Use resolve() and unresolve() methods rather than directly setting resolved property for proper metadata handling
- The get_author() method performs a database lookup, so cache results if calling multiple times
- get_replies() and notify_mentioned_users() return default values in base class - subclasses should override
- parent_comment_uid creates a threading relationship - use is_reply() to check if comment is a reply
- Location and page properties allow spatial/positional references within documents
- Always check if save() returns True to confirm successful persistence
- The _data dictionary is the single source of truth for all comment state
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
class ApprovalComment_v2 75.8% similar
-
class ApprovalComment_v1 73.8% similar
-
class ReviewComment 72.7% similar
-
class ApprovalComment 72.4% similar
-
class ReviewComment_v1 71.7% similar