🔍 Code Extractor

function get_user_access_url

Maturity: 66

Retrieves a share URL for a document version and determines the appropriate access level (read/write) for a specific user based on their role (owner, author, reviewer, approver) and the document's current status.

File:
/tf/active/vicechatdev/CDocs/controllers/share_controller.py
Lines:
864 - 1041
Complexity:
complex

Purpose

This function serves as a centralized access control mechanism for document versions. It evaluates user roles and document workflow states (draft, in review, in approval) to determine whether a user should have write access or read-only access. It handles complex scenarios like sequential reviews, active reviewer assignments, and completed review cycles. The function is read-only and does not modify permissions, only retrieves and returns access information.

Source Code

def get_user_access_url(document_version: DocumentVersion, user_uid: str) -> Dict[str, Any]:
    """
    Get a share URL for a user and determine appropriate access level based on roles.
    This function only retrieves information and does not modify permissions.
    
    Args:
        document_version: The document version to access
        user_uid: UID of the user requesting access
        
    Returns:
        Dict: Access result with URL and permission information if successful
    """
    try:
        # Get document
        document = document_version.document
        if not document:
            return {
                'success': False,
                'message': 'Document not found for version'
            }
        
        # Determine user role and permissions
        is_owner = False
        is_reviewer = False
        is_approver = False
        should_have_write_access = False
        
        # Check if user is the owner
        if hasattr(document, 'owner') and document.owner:
            is_owner = (user_uid == document.owner.UID)
        
        # Check if user is an author (not owner)
        is_author = False
        if hasattr(document, 'authors'):
            for author in document.authors:
                if author and user_uid == author.UID and (not is_owner):
                    is_author = True
                    break
        
        # Check review status
        if document.status == STATUS_IN_REVIEW:
            # Use the direct database query approach from permission_startup_check.py
            from CDocs.models.review import ReviewCycle
            from CDocs.db import db_operations
            
            # Get active review cycles for this document version
            review_cycles = []
            review_query = db_operations.run_query(
                """
                MATCH (v:DocumentVersion {UID: $version_uid})<-[:FOR_REVIEW]-(r:ReviewCycle)
                WHERE r.status IN ['PENDING', 'IN_PROGRESS']
                RETURN r.UID as review_uid
                """,
                {"version_uid": document_version.uid}
            )
            
            if review_query:
                review_cycles = [ReviewCycle(uid=record["review_uid"]) for record in review_query]
                
                # Check if user is an active reviewer in any of these cycles
                for review_cycle in review_cycles:
                    if review_cycle and review_cycle.status in ['PENDING', 'IN_PROGRESS']:
                        reviewer_assignments = review_cycle.get_reviewer_assignments()
                        
                        for assignment in reviewer_assignments:
                            if assignment and assignment.reviewer_uid == user_uid:
                                is_reviewer = True
                                
                                
                                # For sequential reviews, only the active reviewer should have write access
                                #logger.info("checking if review is sequential based on status", review_cycle.sequential)
                                if review_cycle.sequential:
                                    is_reviewer_active = assignment.status == 'ACTIVE'
                                else:
                                    is_reviewer_active = assignment.status in ['ACTIVE', 'PENDING']
                                
                                # Set write access flag if reviewer is active
                                if is_reviewer_active:
                                    should_have_write_access = True
                                break
        
        # Check approval status
        if document.status == STATUS_IN_APPROVAL:
            # Use the direct database query approach from permission_startup_check.py
            from CDocs.models.approval import ApprovalCycle
            from CDocs.db import db_operations
            
            # Get approval cycles associated with this document version
            approval_cycles = []
            approval_query = db_operations.run_query(
                """
                MATCH (v:DocumentVersion {UID: $version_uid})<-[:FOR_APPROVAL]-(a:ApprovalCycle)
                WHERE a.status IN ['PENDING', 'IN_PROGRESS', 'IN_APPROVAL']
                RETURN a.UID as approval_uid
                """,
                {"version_uid": document_version.uid}
            )
            
            if approval_query:
                approval_cycles = [ApprovalCycle(uid=record["approval_uid"]) for record in approval_query]
                
                # Check if user is an active approver in any of these cycles
                for approval_cycle in approval_cycles:
                    if approval_cycle and approval_cycle.status not in ['COMPLETED', 'REJECTED', 'CANCELLED']:
                        approver_assignments = approval_cycle.get_approver_assignments()
                        
                        for assignment in approver_assignments:
                            if assignment and not assignment.removal_date and assignment.approver_uid == user_uid:
                                is_approver = True
                                # Approvers always get read-only access
                                break
        
        # Grant write access to owner and authors only in draft status
        if (is_owner or is_author) and document.status == STATUS_DRAFT:
            should_have_write_access = True

        # NEW CONDITION: Grant write access to owner and authors if document is IN_REVIEW 
        # but all review cycles are completed or cancelled
        if (is_owner or is_author) and document.status == STATUS_IN_REVIEW:
            # Find if there are any active reviews
            has_active_reviews = False
            
            # Query for review cycles related to this document version
            from CDocs.db import db_operations as db
            review_query = db.run_query(
                """
                MATCH (v:DocumentVersion {UID: $version_uid})<-[:FOR_REVIEW]-(r:ReviewCycle)
                WHERE not(r.status IN ['COMPLETED', 'CANCELED'])
                RETURN count(r) as active_count
                """,
                {"version_uid": document_version.uid}
            )
            
            if review_query and review_query[0].get('active_count', 0) > 0:
                has_active_reviews = True
                
            # If no active reviews, grant write access
            if not has_active_reviews:
                should_have_write_access = True
                logger.debug(f"Granting write access to {user_uid} for IN_REVIEW document with no active reviews")
                
        # Get share URL without modifying anything
        share_url = None
        if is_owner:
            logger.info("Owner detected, generating share URL")
            from CDocs.controllers.document_controller import get_document_edit_url
            share_url=get_document_edit_url(document_uid=document.UID)
            if share_url['success']:
                share_url = share_url['edit_url']
            else:
                share_url = None
        else:
            share_url = document_version.share_url
        if not share_url:
            logger.warning(f"Document version {document_version.uid} has no share URL")
            return {
                'success': False,
                'message': 'Document has no share URL'
            }
        
        # Return the access information without modifying permissions
        return {
            'success': True,
            'share_url': share_url,
            'write_access': should_have_write_access,
            'is_owner': is_owner,
            'is_author': is_author,
            'is_reviewer': is_reviewer,
            'is_approver': is_approver,
            'current_status': document_version.status
        }
        
    except Exception as e:
        logger.error(f"Error getting user access URL: {str(e)}")
        return {
            'success': False,
            'message': f'Error getting access URL: {str(e)}'
        }

Parameters

Name Type Default Kind
document_version DocumentVersion - positional_or_keyword
user_uid str - positional_or_keyword

Parameter Details

document_version: A DocumentVersion object representing the specific version of a document for which access is being requested. Must have a valid 'document' relationship and 'uid' attribute. The object should contain status information and relationships to review/approval cycles.

user_uid: A string representing the unique identifier (UID) of the user requesting access to the document. This UID is used to match against document owners, authors, reviewers, and approvers to determine the user's role and access level.

Return Value

Type: Dict[str, Any]

Returns a dictionary with access information. On success: {'success': True, 'share_url': str (URL to access document), 'write_access': bool (whether user can edit), 'is_owner': bool, 'is_author': bool, 'is_reviewer': bool, 'is_approver': bool, 'current_status': str (document status)}. On failure: {'success': False, 'message': str (error description)}. Write access is granted to owners/authors in DRAFT status, active reviewers in IN_REVIEW status (considering sequential vs parallel reviews), and owners/authors when all review cycles are completed/cancelled.

Dependencies

  • CDocs.models.document
  • CDocs.models.user_extensions
  • CDocs.models.review
  • CDocs.models.approval
  • CDocs.models.document_status
  • CDocs.controllers.filecloud_controller
  • CDocs.controllers.document_controller
  • CDocs.db.db_operations
  • logging
  • typing

Required Imports

from typing import Dict, Any
from CDocs.models.document import DocumentVersion
import logging

Conditional/Optional Imports

These imports are only needed under specific conditions:

from CDocs.models.review import ReviewCycle

Condition: only when document status is STATUS_IN_REVIEW

Required (conditional)
from CDocs.db import db_operations

Condition: only when document status is STATUS_IN_REVIEW or STATUS_IN_APPROVAL

Required (conditional)
from CDocs.models.approval import ApprovalCycle

Condition: only when document status is STATUS_IN_APPROVAL

Required (conditional)
from CDocs.controllers.document_controller import get_document_edit_url

Condition: only when user is the document owner

Required (conditional)

Usage Example

from CDocs.models.document import DocumentVersion
from typing import Dict, Any
import logging

logger = logging.getLogger(__name__)

# Assume document_version and user_uid are already obtained
document_version = DocumentVersion(uid='doc_version_123')
user_uid = 'user_456'

# Get access information for the user
access_info = get_user_access_url(document_version, user_uid)

if access_info['success']:
    print(f"Share URL: {access_info['share_url']}")
    print(f"Write Access: {access_info['write_access']}")
    print(f"User Roles - Owner: {access_info['is_owner']}, Author: {access_info['is_author']}")
    print(f"User Roles - Reviewer: {access_info['is_reviewer']}, Approver: {access_info['is_approver']}")
    print(f"Document Status: {access_info['current_status']}")
    
    # Use the share URL to redirect user or display access link
    if access_info['write_access']:
        print("User can edit the document")
    else:
        print("User has read-only access")
else:
    print(f"Error: {access_info['message']}")

Best Practices

  • This function is read-only and does not modify permissions or database state - use it for access checks only
  • Ensure the DocumentVersion object is fully loaded with its document relationship before calling this function
  • The function handles multiple edge cases: sequential vs parallel reviews, completed review cycles, and multiple approval cycles
  • Write access logic is status-dependent: DRAFT (owner/author), IN_REVIEW (active reviewers or owner/author if no active reviews), IN_APPROVAL (no write access)
  • For sequential reviews, only the reviewer with 'ACTIVE' status gets write access; for parallel reviews, both 'ACTIVE' and 'PENDING' reviewers get access
  • Always check the 'success' field in the returned dictionary before accessing other fields
  • The function uses direct Cypher queries for performance when checking review and approval cycles
  • Owners receive special treatment with a different URL generation method (get_document_edit_url)
  • Consider caching the result if calling this function multiple times for the same user and document version within a short time period
  • The function logs warnings and errors - ensure logging is properly configured to capture these messages for debugging

Similar Components

AI-powered semantic similarity - components with related functionality:

  • function manage_user_share_access 77.5% similar

    Manages user access permissions (read-only or edit) to a specific document version share in FileCloud, creating the share if it doesn't exist.

    From: /tf/active/vicechatdev/CDocs/controllers/filecloud_helper.py
  • function manage_user_share_access_v2 76.9% similar

    Manages user access permissions to a FileCloud document share, creating shares if needed and setting read-only or write access for specified users.

    From: /tf/active/vicechatdev/CDocs/controllers/permission_startup_check.py
  • function get_document_access 75.8% similar

    Retrieves document access information for a specific user, including permissions (write access, owner, reviewer, approver status) and share URL.

    From: /tf/active/vicechatdev/CDocs/controllers/api_handler.py
  • function manage_user_share_access_v1 75.3% similar

    Manages user access permissions to a FileCloud document share, creating the share if needed and setting read-only or write access for a specified user.

    From: /tf/active/vicechatdev/CDocs/controllers/filecloud_controller.py
  • function remove_user_access 70.0% similar

    Removes a user's access permissions from a specific document version share in FileCloud by delegating to the FileCloud client's remove_user_from_share method.

    From: /tf/active/vicechatdev/CDocs/controllers/share_controller.py
← Back to Browse