3
(h)                 @   s   d dl mZ d dlmZ d dlmZ d dlm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
lmZ d dlmZ d dlmZ G dd deZG dd deZG dd deZG dd deeZG dd deeZdd ZdS )    )unicode_literals)wraps)chain)url)messages)reverse)QuerySet)Http404HttpResponseRedirect)HttpResponseBase)View)SingleObjectMixin)MultipleObjectMixinc                   sp   e Zd ZdZg Zg ZdZ fddZd fdd	Zd fdd		Z	d
d Z
dd Zdd Zdd Zdd Z  ZS )BaseDjangoObjectActionsa  
    ModelAdmin mixin to add new actions just like adding admin actions.

    Attributes
    ----------
    model : django.db.models.Model
        The Django Model these actions work on. This is populated by Django.
    change_actions : list of str
        Write the names of the methods of the model admin that can be used as
        tools in the change view.
    changelist_actions : list of str
        Write the names of the methods of the model admin that can be used as
        tools in the changelist view.
    tools_view_name : str
        The name of the Django Object Actions admin view, including the 'admin'
        namespace. Populated by `_get_action_urls`.
    Nc                s   t t| j }| j | S )z)Prepend `get_urls` with our own patterns.)superr   get_urls_get_action_urls)selfurls)	__class__ N/tmp/pip-install-q3hcpn_q/django-object-actions/django_object_actions/utils.pyr   *   s    z BaseDjangoObjectActions.get_urls c                sH   |pi }|j  fdd j|||D  jd tt j||||S )Nc                s   g | ]} j |qS r   )_get_tool_dict).0action)r   r   r   
<listcomp>3   s    z7BaseDjangoObjectActions.change_view.<locals>.<listcomp>)objectactionstools_view_name)updateget_change_actionsr   r   r   change_view)r   request	object_idform_urlextra_context)r   )r   r   r!   /   s    

z#BaseDjangoObjectActions.change_viewc                s@   |pi }|j  fdd j|D  jd tt j||S )Nc                s   g | ]} j |qS r   )r   )r   r   )r   r   r   r   ?   s    z;BaseDjangoObjectActions.changelist_view.<locals>.<listcomp>)r   r   )r   get_changelist_actionsr   r   r   changelist_view)r   r"   r%   )r   )r   r   r'   ;   s    

z'BaseDjangoObjectActions.changelist_viewc             C   s   | j S )a>  
        Override this to customize what actions get to the change view.

        This takes the same parameters as `change_view`.

        For example, to restrict actions to superusers, you could do:

            class ChoiceAdmin(DjangoObjectActions, admin.ModelAdmin):
                def get_change_actions(self, request, **kwargs):
                    if request.user.is_superuser:
                        return super(ChoiceAdmin, self).get_change_actions(
                            request, **kwargs
                        )
                    return []
        )change_actions)r   r"   r#   r$   r   r   r   r    J   s    z*BaseDjangoObjectActions.get_change_actionsc             C   s   | j S )zU
        Override this to customize what actions get to the changelist view.
        )changelist_actions)r   r"   r   r   r   r&   \   s    z.BaseDjangoObjectActions.get_changelist_actionsc          
   C   s   i }| j jj}d| j jj|f }d| }d| | _x$t| j| jD ]}t| |||< qBW t	d| j
jtj| j |d| | j
jd|dt	d| j
jtj| j |d	| | j
jd|dgS )
z6Get the url patterns that route each action to a view.z%s_%sz
%s_actionszadmin:z#^(?P<pk>.+)/actions/(?P<tool>\w+)/$zadmin:%s_change)modelactionsbackcurrent_app)namez^actions/(?P<tool>\w+)/$zadmin:%s_changelist)r*   _meta
model_nameZ	app_labelr   r   r(   r)   getattrr   Z
admin_siteZ
admin_viewChangeActionViewZas_viewr.   ChangeListActionView)r   r+   r0   Zbase_url_nameZmodel_actions_url_namer   r   r   r   r   e   s.    

z(BaseDjangoObjectActions._get_action_urlsc             C   s0   t | |}| j|\}}t|t |d|||dS )z.Represents the tool as a dict with extra meta.label)r.   r4   standard_attrscustom_attrs)r1   _get_button_attrsdict)r   Z	tool_nametoolr5   r6   r   r   r   r      s    

z&BaseDjangoObjectActions._get_tool_dictc             C   s   t |di }d|kr|jd d|kr0|jd |jddt |ddd}i }i }x6t|f|j D ]"\}}||kr~|||< qd|||< qdW ||fS )a=  
        Get the HTML attributes associated with a tool.

        There are some standard attributes (class and title) that the template
        will always want. Any number of additional attributes can be specified
        and passed on. This is kinda awkward and due for a refactor for
        readability.
        attrshreftitleclassr   Zshort_description)r=   r<   )r1   popgetr8   items)r   r9   r:   Zdefault_attrsr5   r6   kvr   r   r   r7      s    	



z)BaseDjangoObjectActions._get_button_attrs)r   N)N)__name__
__module____qualname____doc__r(   r)   r   r   r!   r'   r    r&   r   r   r7   __classcell__r   r   )r   r   r      s   	+r   c               @   s   e Zd ZdZdZdS )DjangoObjectActionsz&django_object_actions/change_form.htmlz&django_object_actions/change_list.htmlN)rC   rD   rE   Zchange_form_templateZchange_list_templater   r   r   r   rH      s   rH   c               @   sL   e Zd ZdZdZdZdZdZedd Z	edd Z
dd ZeZd	d
 ZdS )BaseActionViewa  
    The view that runs a change/changelist action callable.

    Attributes
    ----------
    back : str
        The urlpattern name to send users back to. This is set in
        `_get_action_urls` and turned into a url with the `back_url` property.
    model : django.db.model.Model
        The model this tool operates on.
    actions : dict
        A mapping of action names to callables.
    Nc             C   s   t dS )z
        tuple: The argument(s) to send to the action (excluding `request`).

        Change actions are called with `(request, obj)` while changelist
        actions are called with `(request, queryset)`.
        N)NotImplementedError)r   r   r   r   	view_args   s    zBaseActionView.view_argsc             C   s   t dS )z
        str: The url path the action should send the user back to.

        If an action does not return a http response, we automagically send
        users back to either the change or the changelist page.
        N)rJ   )r   r   r   r   back_url   s    zBaseActionView.back_urlc             K   sT   y| j | }W n tk
r*   tdY nX ||f| j }t|trJ|S t| jS )NzAction does not exist)r+   KeyErrorr	   rK   
isinstancer   r
   rL   )r   r"   r9   kwargsviewretr   r   r   r?      s    
zBaseActionView.getc             C   s   t j|| dS )z
        Mimic Django admin actions's `message_user`.

        Like the second example:
        https://docs.djangoproject.com/en/1.9/ref/contrib/admin/actions/#custom-admin-action
        N)r   info)r   r"   messager   r   r   message_user   s    zBaseActionView.message_user)rC   rD   rE   rF   r,   r*   r+   r-   propertyrK   rL   r?   postrT   r   r   r   r   rI      s   

rI   c               @   s$   e Zd Zedd Zedd ZdS )r2   c             C   s
   | j  fS )N)Z
get_object)r   r   r   r   rK     s    zChangeActionView.view_argsc             C   s   t | j| jd f| jdS )Npk)argsr-   )r   r,   rO   r-   )r   r   r   r   rL     s    zChangeActionView.back_urlN)rC   rD   rE   rU   rK   rL   r   r   r   r   r2      s   r2   c               @   s$   e Zd Zedd Zedd ZdS )r3   c             C   s
   | j  fS )N)get_queryset)r   r   r   r   rK     s    zChangeListActionView.view_argsc             C   s   t | j| jdS )N)r-   )r   r,   r-   )r   r   r   r   rL     s    zChangeListActionView.back_urlN)rC   rD   rE   rU   rK   rL   r   r   r   r   r3   
  s   r3   c                s   t   fdd}|S )z>Decorator that makes standard Django admin actions compatible.c                s~   t |tsry| j|j|jd}W nN tk
rp   y|jj}W n tk
rZ   |jj}Y nX |j	j|jd}Y nX  | ||S )N)rW   )
rN   r   rY   filterrW   AttributeErrorr/   r*   Zconcrete_modelZobjects)r   r"   Zquerysetr*   )funcr   r   decorated_function  s    
z6takes_instance_or_queryset.<locals>.decorated_function)r   )r\   r]   r   )r\   r   takes_instance_or_queryset  s    r^   N) 
__future__r   	functoolsr   	itertoolsr   Zdjango.conf.urlsr   Zdjango.contribr   Zdjango.core.urlresolversr   Zdjango.db.models.queryr   Zdjango.httpr	   r
   Zdjango.http.responser   Zdjango.views.genericr   Zdjango.views.generic.detailr   Zdjango.views.generic.listr   objectr   rH   rI   r2   r3   r^   r   r   r   r   <module>   s$    +@

