o
    Ci!                     @   s   d Z ddlmZ ddlmZ ddlmZ ddlmZm	Z	 ddl
mZ dd	 Zd
d Zdd Zdd Zdd ZddlmZ dd Zdd Zdd ZG dd dZdd ZddlmZ ddlmZ ddlmZ G dd  d eZdS )!z7
Permission checking utilities and decorators for RBAC
    wraps)JsonResponse)cache   )UserProfile
PermissionNc                 C   sV   | j jrdS d| j j d| }t|}|dur|S || jv r)t|dd dS dS )z
    Check if user has a specific permission
    
    Args:
        user: UserProfile instance
        permission_code: String like 'flowboard.create'
    
    Returns:
        Boolean indicating if user has permission
    Tuser_perms__N,  F)useris_superuseridr   getcustom_permissionsset)requestpermission_code	cache_keycached_result r   1/var/www/Datamplify/authentication/permissions.pyhas_permission   s   

r   c                       t  fdd|D S )z
    Check if user has any of the specified permissions
    
    Args:
        user: UserProfile instance
        permission_codes: List of permission codes
    
    Returns:
        Boolean indicating if user has at least one permission
    c                 3       | ]}t  |V  qd S Nr   .0coder   r   r   	<genexpr>A       z%has_any_permission.<locals>.<genexpr>)anyr   permission_codesr   r    r   has_any_permission6      r&   c                    r   )z
    Check if user has all of the specified permissions
    
    Args:
        user: UserProfile instance
        permission_codes: List of permission codes
    
    Returns:
        Boolean indicating if user has all permissions
    c                 3   r   r   r   r   r    r   r   r!   O   r"   z&has_all_permissions.<locals>.<genexpr>)allr$   r   r    r   has_all_permissionsD   r'   r)   c                 C   s   | j rttjjdddS d| j }t|}|dur|S tjj	| d
dd}t }|D ]}||jjjddd q0t|}t||d	 |S )
z
    Get all permission codes for a user
    
    Args:
        user: UserProfile instance
    
    Returns:
        List of permission codes
    r   Tflatuser_all_perms_Nr    rolerole__permissionsr   )r   listr   objectsvalues_listr   r   r   r   filterselect_relatedprefetch_relatedr   updater-   permissions)r   r   cached_perms
user_rolesr%   	user_rolepermission_listr   r   r   get_user_permissionsR   s   

r;   c                 C   s*   t d| j d t d| j  dS )z'Clear all cached permissions for a userr	   z_*r,   N)r   delete_patternr   deleter    r   r   r   clear_user_permission_cachet   s   r>   )Applicationc                        fdd}|S )z
    Decorator to require a specific permission for a view
    
    Usage:
        @require_permission('flowboard.create')
        def create_flowboard(request):
            ...
    c                       t   fdd}|S )Nc                    sN   | j jstdddddS t|  r| g|R i |S tdd dd	dS )
NAuthentication requiredz-You must be logged in to access this resourceerrormessage  statusPermission deniedz1You do not have permission to perform this action)rD   rE   required_permission  )r   is_authenticatedr   r   r   argskwargs)r   	view_funcr   r   wrapper   s    
z6require_permission.<locals>.decorator.<locals>.wrapperr   rP   rQ   r   rP   r   	decorator   s   z%require_permission.<locals>.decoratorr   )r   rU   r   rS   r   require_permission|   s   	rV   c                     r@   )z
    Decorator to require any of the specified permissions
    
    Usage:
        @require_any_permission('flowboard.edit', 'flowboard.delete')
        def modify_flowboard(request):
            ...
    c                    rA   )Nc                    P   | j jstddiddS t| j  r| g|R i |S tdt dddS NrD   rB   rF   rG   rI   )rD   required_permissionsrK   )r   rL   r   r&   r/   rM   r%   rP   r   r   rQ         z:require_any_permission.<locals>.decorator.<locals>.wrapperr   rR   r%   rT   r   rU         z)require_any_permission.<locals>.decoratorr   r%   rU   r   r\   r   require_any_permission      	r_   c                     r@   )z
    Decorator to require all of the specified permissions
    
    Usage:
        @require_all_permissions('user.edit', 'user.manage_roles')
        def assign_role_to_user(request):
            ...
    c                    rA   )Nc                    rW   rX   )r   rL   r   r)   r/   rM   rZ   r   r   rQ      r[   z;require_all_permissions.<locals>.decorator.<locals>.wrapperr   rR   r\   rT   r   rU      r]   z*require_all_permissions.<locals>.decoratorr   r^   r   r\   r   require_all_permissions   r`   ra   c                   @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )PermissionMixinzb
    Mixin to add permission checking methods to request object
    Can be used in middleware
    c                 C      t | j|S r   )r   r   )selfr   r   r   r   r         zPermissionMixin.has_permissionc                 G   rc   r   )r&   r   rd   r%   r   r   r   r&      re   z"PermissionMixin.has_any_permissionc                 G   rc   r   )r)   r   rf   r   r   r   r)      re   z#PermissionMixin.has_all_permissionsc                 C   s
   t | jS r   )r;   r   )rd   r   r   r   get_permissions   s   
zPermissionMixin.get_permissionsN)__name__
__module____qualname____doc__r   r&   r)   rg   r   r   r   r   rb      s    rb   c                 C   sP   d|  }t |}|d u r&ttjjj| d jddd}t ||d |S )Nzuser_perms:)roles__usersr   Tr*   r   )	r   r   r   auth_modelsr   r0   r2   distinctr1   )user_idkeypermsr   r   r   get_user_custom_permissions   s   


rr   )IsAuthenticated)AuthenticationFailedc                   @   s   e Zd ZdZdd ZdS )CustomIsAuthenticatedz3Access denied: Please provide a valid access token.c                 C   sb   |j d u rtddd|j jjtjkr|j jj|_|jr!|jjs(tdddt|jj	|_
dS )Nunauthorizedz5Access token missing or invalid. Please log in again.rC   T)authrt   applicationauthorization_grant_typer?   GRANT_CLIENT_CREDENTIALSr   rL   rr   r   r   )rd   r   viewr   r   r   r     s   
z$CustomIsAuthenticated.has_permissionN)rh   ri   rj   rE   r   r   r   r   r   ru      s    ru   )rk   	functoolsr   django.httpr   django.core.cacher   modelsr   r   authentication.modelsrm   r   r&   r)   r;   r>   oauth2_provider.modelsr?   rV   r_   ra   rb   rr   rest_framework.permissionsrs   rest_framework.exceptionsrt   ru   r   r   r   r   <module>   s*    +"!