class ReviewComment
A model class representing a comment made during document review, with support for resolution tracking and database persistence.
/tf/active/vicechatdev/CDocs/models/review.py
22 - 216
moderate
Purpose
ReviewComment manages review comments in a document management system. It handles creation, storage, and retrieval of comments made during review cycles, including tracking whether comments require resolution, storing resolution text and dates, and maintaining relationships with review cycles and commenters. The class provides database persistence through Neo4j and integrates with the DocUser model for commenter information.
Source Code
class ReviewComment(BaseModel):
"""Model representing a comment made during document review."""
def __init__(self, data: Optional[Dict[str, Any]] = None, uid: Optional[str] = None):
"""
Initialize a review comment.
Args:
data: Dictionary of comment properties
uid: Comment UID to load from database (if data not provided)
"""
if data is None and uid is not None:
# Fetch comment data from database
data = db.get_node_by_uid(uid)
super().__init__(data or {})
@classmethod
def create(cls, review_cycle_uid: str,
commenter: Union[DocUser, str],
text: str,
requires_resolution: bool = False,
properties: Optional[Dict[str, Any]] = None) -> Optional['ReviewComment']:
"""
Create a new review comment.
Args:
review_cycle_uid: UID of the review cycle this comment belongs to
commenter: User making the comment or their UID
text: Comment text
requires_resolution: Whether this comment requires resolution
properties: Additional properties for the comment
Returns:
New ReviewComment instance or None if creation failed
"""
try:
# Prepare properties
props = properties or {}
props.update({
'text': text,
'timestamp': datetime.now(),
'requiresResolution': requires_resolution,
'commenterUID': commenter.uid if isinstance(commenter, DocUser) else commenter
})
# Create the comment node first
comment_uid = str(uuid.uuid4())
props['UID'] = comment_uid
# Create node in database
success = db.create_node(NodeLabels.REVIEW_COMMENT, props)
if not success:
logger.error(f"Failed to create review comment for review cycle {review_cycle_uid}")
return None
# Create relationship: Comment -> COMMENTED_ON -> Review Cycle
rel_success = db.create_relationship(
comment_uid,
review_cycle_uid,
RelTypes.COMMENTED_ON
)
if not rel_success:
logger.error(f"Failed to create relationship between comment {comment_uid} and review cycle {review_cycle_uid}")
# Clean up the orphaned comment node
db.delete_node(comment_uid)
return None
# Create the comment instance
comment = cls(props)
return comment
except Exception as e:
logger.error(f"Error creating review comment: {e}")
return None
def save(self) -> bool:
"""Save changes to database."""
try:
# If node doesn't exist, create it
if not db.node_exists(self.uid):
created = db.create_node_with_uid(
NodeLabels.REVIEW_COMMENT,
self._data,
self.uid
)
if created and self._data.get('review_cycle_uid'):
# Create relationship between comment and review cycle
db.create_relationship(
self.uid,
self._data['review_cycle_uid'],
RelTypes.COMMENTED_ON
)
return created
# Otherwise update existing node
return db.update_node(self.uid, self._data)
except Exception as e:
logger.error(f"Error saving review comment: {e}")
return False
@property
def text(self) -> str:
"""Get comment text."""
return self._data.get('text', '')
@property
def timestamp(self) -> Optional[datetime]:
"""Get when comment was made."""
return self._data.get('timestamp')
@property
def requires_resolution(self) -> bool:
"""Whether comment requires resolution."""
return self._data.get('requiresResolution', False)
@property
def resolution(self) -> Optional[str]:
"""Get resolution text."""
return self._data.get('resolution')
@resolution.setter
def resolution(self, text: str) -> None:
"""Set resolution text."""
self._data['resolution'] = text
self._data['resolutionDate'] = datetime.now()
db.update_node(self.uid, {
'resolution': text,
'resolutionDate': self._data['resolutionDate']
})
@property
def resolution_date(self) -> Optional[datetime]:
"""Get when comment was resolved."""
return self._data.get('resolutionDate')
@property
def is_resolved(self) -> bool:
"""Whether comment has been resolved."""
return self.resolution is not None
@property
def commenter_uid(self) -> Optional[str]:
"""Get UID of user who made the comment."""
return self._data.get('commenterUID')
@property
def commenter(self) -> Optional[DocUser]:
"""Get user who made the comment."""
commenter_uid = self.commenter_uid
if commenter_uid:
return DocUser(uid=commenter_uid)
return None
@property
def review_cycle_uid(self) -> Optional[str]:
"""Get the UID of the review cycle this comment belongs to."""
# First check if we already have it in properties
if self._data.get('review_cycle_uid'):
return self._data.get('review_cycle_uid')
# Otherwise query the database
result = db.run_query(
"""
MATCH (c:ReviewComment {UID: $uid})-[:COMMENTED_ON]->(r:ReviewCycle)
RETURN r.UID as review_uid
""",
{"uid": self.uid}
)
if result and 'review_uid' in result[0]:
# Cache it for future use
self._data['review_cycle_uid'] = result[0]['review_uid']
return result[0]['review_uid']
return None
def to_dict(self) -> Dict[str, Any]:
"""Convert to dictionary representation."""
result = super().to_dict()
# Add commenter information if available
commenter = self.commenter
if commenter:
result['commenter'] = {
'UID': commenter.uid,
'name': commenter.name,
'email': commenter.email
}
return result
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
bases |
BaseModel | - |
Parameter Details
data: Optional dictionary containing comment properties (text, timestamp, requiresResolution, commenterUID, etc.). If provided, initializes the comment with these properties. If None and uid is provided, data will be fetched from database.
uid: Optional unique identifier string for the comment. If provided without data, the comment will be loaded from the database using this UID.
Return Value
The __init__ method returns a ReviewComment instance. The create() class method returns a new ReviewComment instance if successful, or None if creation failed. The save() method returns a boolean indicating success. Properties return their respective types (str, datetime, bool, DocUser, etc.).
Class Interface
Methods
__init__(self, data: Optional[Dict[str, Any]] = None, uid: Optional[str] = None)
Purpose: Initialize a review comment instance, either from provided data or by loading from database using UID
Parameters:
data: Dictionary of comment properties to initialize withuid: Comment UID to load from database if data not provided
Returns: None (constructor)
create(cls, review_cycle_uid: str, commenter: Union[DocUser, str], text: str, requires_resolution: bool = False, properties: Optional[Dict[str, Any]] = None) -> Optional['ReviewComment']
Purpose: Create a new review comment in the database with proper relationships to review cycle
Parameters:
review_cycle_uid: UID of the review cycle this comment belongs tocommenter: DocUser instance or UID string of the user making the commenttext: The comment text contentrequires_resolution: Boolean flag indicating if this comment needs to be resolved (default False)properties: Additional properties to store with the comment
Returns: New ReviewComment instance if successful, None if creation failed
save(self) -> bool
Purpose: Persist comment changes to the database, creating node if it doesn't exist or updating if it does
Returns: Boolean indicating whether save operation was successful
text(self) -> str
property
Purpose: Get the comment text content
Returns: String containing the comment text, empty string if not set
timestamp(self) -> Optional[datetime]
property
Purpose: Get the datetime when the comment was created
Returns: datetime object of when comment was made, or None if not set
requires_resolution(self) -> bool
property
Purpose: Check if this comment requires resolution
Returns: Boolean indicating whether comment requires resolution (default False)
resolution(self) -> Optional[str]
property
Purpose: Get the resolution text for this comment
Returns: String containing resolution text, or None if not resolved
resolution(self, text: str) -> None
property
Purpose: Set the resolution text and automatically update resolution date in database
Parameters:
text: The resolution text to set
Returns: None (setter automatically persists to database)
resolution_date(self) -> Optional[datetime]
property
Purpose: Get the datetime when the comment was resolved
Returns: datetime object of when comment was resolved, or None if not resolved
is_resolved(self) -> bool
property
Purpose: Check if the comment has been resolved
Returns: Boolean indicating whether comment has resolution text set
commenter_uid(self) -> Optional[str]
property
Purpose: Get the UID of the user who made the comment
Returns: String UID of the commenter, or None if not set
commenter(self) -> Optional[DocUser]
property
Purpose: Get the DocUser instance of the user who made the comment
Returns: DocUser instance of the commenter, or None if commenter UID not set
review_cycle_uid(self) -> Optional[str]
property
Purpose: Get the UID of the review cycle this comment belongs to, querying database if needed and caching result
Returns: String UID of the review cycle, or None if relationship not found
to_dict(self) -> Dict[str, Any]
Purpose: Convert the comment to a dictionary representation including commenter information
Returns: Dictionary containing all comment data plus nested commenter information (UID, name, email)
Attributes
| Name | Type | Description | Scope |
|---|---|---|---|
_data |
Dict[str, Any] | Internal dictionary storing all comment properties (inherited from BaseModel) | instance |
uid |
str | Unique identifier for the comment (inherited from BaseModel) | instance |
Dependencies
logginguuidtypingdatetimeCDocs.dbCDocs.configCDocs.db.schema_managerCDocs.models.baseCDocs.models.user_extensionsCDocs.models.document
Required Imports
import logging
import uuid
from typing import Dict, List, Any, Optional, Union, Set
from datetime import datetime, timedelta
from CDocs import db
from CDocs.config import settings
from CDocs.db.schema_manager import NodeLabels, RelTypes
from CDocs.models.base import BaseModel, register_model
from CDocs.models.user_extensions import DocUser
Usage Example
# Create a new review comment
comment = ReviewComment.create(
review_cycle_uid='cycle-123',
commenter='user-456',
text='This section needs clarification',
requires_resolution=True
)
# Load existing comment from database
existing_comment = ReviewComment(uid='comment-789')
# Access comment properties
print(comment.text)
print(comment.timestamp)
print(comment.requires_resolution)
# Get commenter information
commenter = comment.commenter
if commenter:
print(f'Comment by: {commenter.name}')
# Resolve a comment
if comment.requires_resolution:
comment.resolution = 'Updated section with additional details'
comment.save()
# Check resolution status
if comment.is_resolved:
print(f'Resolved on: {comment.resolution_date}')
# Convert to dictionary for serialization
comment_dict = comment.to_dict()
Best Practices
- Always use the create() class method to create new comments rather than direct instantiation, as it handles database relationships properly
- Check return values from create() and save() methods for None/False to handle failures gracefully
- Use the resolution property setter to resolve comments, as it automatically updates the resolution date and persists to database
- The class automatically handles database synchronization when setting the resolution property
- Load comments by UID when you need to work with existing comments: ReviewComment(uid='comment-id')
- The commenter property performs a database lookup, so cache the result if using multiple times
- The review_cycle_uid property caches its result after first lookup to avoid repeated database queries
- Call save() after modifying comment properties (except resolution which auto-saves) to persist changes
- The class inherits from BaseModel, so it has access to uid and _data attributes from the parent class
- Failed comment creation automatically cleans up orphaned nodes to maintain database integrity
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
class ApprovalComment 80.4% similar
-
class ApprovalComment_v1 80.1% similar
-
class ReviewerAssignment 64.6% similar
-
class ReviewCycle 63.7% similar
-
function add_review_comment 62.6% similar