o k`w@s`ddlZddlmZmZddlmZddlmZddlm Z ddl m Z ddl m Z mZmZddlTdd lmZmZdd lmZdd lmZmZdd lmZmZdd lmZmZm Z m!Z!ddl"m#Z#ddl$m%Z%ddl&m'Z'm(Z(m)Z)ddl*m+Z+ddl,m-Z-m.Z.m/Z/ddl0m1Z1m2Z2ddl3m4Z4m5Z5ddZ6ddZ7ddZ8GdddeZ9Gddde4Z:dS)N) ParsingErrorRawConfigParser) defaultdict)partial)resource_filename)IEnvironmentSetupParticipant) ConfigSection ConfigurationConfigurationError)*)PermissionCachePermissionSystem)ResourceNotFound)ITicketActionController TicketSystem) Component Resolution)exception_to_unicodeget_reporter_idsub_valto_list)tag) separated)_tag_ cleandoc_)RepositoryManager)Chrome add_scriptadd_script_data) MacroErrorProcessorError) WikiMacroBase parse_argsc Csgddddggd}ggd}|}||tt}|D]o\}}|d}|d}t|dkrXzdd|d D\} } Wn tyHYqwt| ||d <| ||d <q|d} | |vsgt|| t rn|||| <qt|| t r~t |||| <qt|| t rt|||| <q| D]9\} } d | vrd | vr| d | d <n | dd| d <| D] \}}| ||qdD] }t| d |dqq|S)z.Given a list of options from [ticket-workflow]r) oldstatesnewstatenamelabeldefault operations permissions) set_ownerset_resolution.cSsg|]}|qS)strip.0xr0r0>/usr/lib/python3/dist-packages/trac/ticket/default_workflow.py Fz)parse_workflow_config..z->r%r&r(r'r )zz< none >N)copyupdaterdictsplitlen ValueErrorr isinstancestrintlistitemsreplacer1 setdefaultr) rawactionsrequired_attrsoptional_attrs known_attrsactionsoptionvaluepartsr'r%r& attributeaction attributeskeyvalr0r0r5parse_workflow_config,s\       rScCst|d}t|}|S)zYUsually passed self.config, this will return the parsed ticket-workflow section. ticket-workflow)rBoptionsrS)config raw_actionsrJr0r0r5get_workflow_configcsrXcCs<tdd|}t|}|dD] \}}|d||qdS)zLoads the ticket-workflow section from the given file (expected to be in the 'workflows' tree) into the provided config. z trac.ticketz workflows/%srTN)rr rUset)rVfilename new_configr'rLr0r0r5load_workflow_config_snippetls r\c@seZdZdZeeeeddZdZ ddZ ddZ d d Z d d Z d dZddZddZddZddZddZddZddZddZdd Zd!d"Zd#d$Zd%S)&ConfigurableTicketWorkflowzTicket action controller which provides actions according to a workflow defined in trac.ini. The workflow is defined in the `[ticket-workflow]` section of the [wiki:TracIni#ticket-workflow-section trac.ini] configuration file. rTa The workflow for tickets is controlled by plugins. By default, there's only a `ConfigurableTicketWorkflow` component in charge. That component allows the workflow to be configured via this section in the `trac.ini` file. See TracWorkflow for more details. ) del_ownerr,set_owner_to_self may_set_ownerr-del_resolution leave_statusreset_workflowcCs||_|jd|jdS)Nz'Workflow actions at initialization: %s )get_all_actionsrJlogdebugselfr0r0r5__init__s z#ConfigurableTicketWorkflow.__init__cCs6d|jvrt|jd|j||_dSdS)zWhen an environment is created, we provide the basic-workflow, unless a ticket-workflow section already exists. rTzbasic-workflow.iniN)rVsectionsr\saverdrJrgr0r0r5environment_createds   z.ConfigurableTicketWorkflow.environment_createdcCdSNr0rgr0r0r5environment_needs_upgradez4ConfigurableTicketWorkflow.environment_needs_upgradecCrmrnr0rgr0r0r5upgrade_environmentrpz.ConfigurableTicketWorkflow.upgrade_environmentcCs(|jd|d}|du}|jd|d}t|d}|j}g}|jD]G\} } | d} | d} d| vr:| dkr:q%t| d krMd | vrM||krM|| krMq%| d } |rX| dgks\|| vrl||| |rl|| d | fq%|rd |jvr|t |j  vr|jd }||||r||d d f|S)zbReturns a list of (weight, action) tuples that are valid for this request and this ticket.statusNownerauthorr*r&rbr r/r_r%r)_reset) _oldgetrresourcerJrCr=_is_action_allowedappendrenvget_all_status)rhreqticket ticket_statusexists ticket_ownerrtrxallowed_actions action_name action_infor*r&r%resetr0r0r5get_ticket_actionss8     z-ConfigurableTicketWorkflow.get_ticket_actionscCs6||}|d}|r|D] }||vrdSq dSdS)zMReturns `True` if the workflow action is allowed for the `resource`. r+FT)perm)rhr}rOrx perm_cacherequired_perms permissionr0r0r5rys z-ConfigurableTicketWorkflow._is_action_allowedcCsTt}|jD]}||d||dq|d|d|d|S)zEReturn a list of all states described by the configuration. r%r&r r$N)rYrJvaluesr:adddiscard)rh all_statusrPr0r0r5r|s   z)ConfigurableTicketWorkflow.get_all_statusc s4|jd||j|}|d}|d}|jd|d}|jd|d}|d} t|d} tt|jj ||j d} tt|jj ||j d| |} |du} t |j}g}g}d |vrj| td | td d |vru| td d|vs~d|vrl||||}d|vr| }n!d|vr| s|j}n|pd}|dur||vr|d|nt|d|}|s|j||}| tdtjd|||dd| r|dur| tdn| td| dnt|dkr,tjd|||dd}| |d}| tdt||d| r|dur| td|dn|d|dkr+| td| |dny|j||| tdtjfdd tfd!d"|DD||d#d| rZ|durb| td$nC| td%| dn9d&|vr| | }| r}|dur| td|dn|| kr| td| |dn|| kr| td'| dd(|vr2d)d t|jD}d(|vrt||d(}tfd*d"|Drttd+|sttd,d-|}t|dkr tjd|||dd}| td.t|d|d/| td0|dd1n%|j||j| td.tjfd2d |D||d#d/| td3d4|vr>| td5d6|vrdt|dkrc| td7|d8| |r^td'| dntd9n|dduru| td:| d1n| |kr| td;| d1|tt|d<t|rt|d=d>fSd?fS)@Nz)render_ticket_action_control: action "%s"r(r*rsrrr&rtrxrczfrom invalid statezCurrent state no longer existsr^zThe ticket will be disownedr,r`raction_%s_reassign_ownerz to %(owner)stext)typeidr'rL)rsz$The owner will be the specified userzFThe owner will be changed from %(current_owner)s to the specified user) current_ownerr/hiddenzThe owner will be %(new_owner)s) new_ownerzAThe owner will be changed from %(current_owner)s to %(new_owner)s)rrcs4g|]\}}tj||dur|nd|kpddqS)Nr$rLselectedrrK)r3rrL)selected_ownerr0r5r61s   zKConfigurableTicketWorkflow.render_ticket_action_control..c3s|] }||fVqdSrnr0)r3rs) format_authorr0r5 3szJConfigurableTicketWorkflow.render_ticket_action_control..)rr'z#The owner will be the selected userzEThe owner will be changed from %(current_owner)s to the selected userr_z'The owner will remain %(current_owner)sr-cSsg|]}|jqSr0r')r3rr0r0r5r6Jsc3s|]}|vVqdSrnr0r2)valid_resolutionsr0r5rNzYour workflow attempts to set a resolution but uses undefined resolutions (configuration issue, please contact your Trac admin).zuYour workflow attempts to set a resolution but none is defined (configuration issue, please contact your Trac admin).action_%s_resolve_resolutionzas %(resolution)s) resolutionz&The resolution will be set to %(name)srcs$g|]}tj|||kp ddqS)Nrrr2)selected_optionr0r5r6fs   zThe resolution will be setrazThe resolution will be deletedrbz as %(status)s)rrz$The ticket will remain with no ownerzThe status will be '%(name)s'zNext status will be '%(name)s'r8z. r.r$) rerfrJrvrwrrrr{ authorinforxrrrzrget_allowed_owners default_ownerinsertAssertionErrorargsrrinputr=selectsortedrrYanyr default_resolutionr)rhr}r~rO this_actionr(r*rr next_statusrt author_infoformatted_current_ownerr ticket_systemcontrolhintsownersrrrsformatted_new_ownerformatted_author resolutionsrr0)rrrrr5render_ticket_action_controlsD                         z7ConfigurableTicketWorkflow.render_ticket_action_controlcCs|j|}||||jsiSi}|d}|dkr||d<|dD]g}|dkr,d|d<q!|dvrW|d }|jd ||rA|d nd} t| tkrN| d } || ||d<q!|d krct|d |d<q!|dkrld|d<q!|dkr|d} |jd|| r| d nd} | |d<q!|j sd|vr||d||d<|S|ddkrd|j vrd|j vrd|vrz t |j |j d} Wn tyY|Sw| jpd} |dpd}| |krt |j |d}|jr|j|d<|S)Nr&r rrr*r^r$rs)r,r`r,rrr_rtrarr-rnew component)rJryrxrwrrrB_sub_owner_keywordrrrrvTicketComponentr{rrs)rhr}r~rOrupdatedrr operationr,newownerr- newresolutionold_comp old_ownerrnew_compr0r0r5get_ticket_changes}sj                 z-ConfigurableTicketWorkflow.get_ticket_changescCrmrnr0)rhr}r~rOr0r0r5apply_action_side_effectsrpz4ConfigurableTicketWorkflow.apply_action_side_effectscCst|j}tdd|D}|r0dddgdgdgd}|D] \}}|d ||q#|D]\}}|d sC|jd |q4|S) Ncss&|]}d|dg|dvVqdS)rr&r%Nr0)r3ar0r0r5rsz=ConfigurableTicketWorkflow.get_all_actions..rResetrrc TICKET_ADMIN)r)r(r&r%r*r+rur&z:Ticket workflow action '%s' doesn't define any transitions) rSticket_workflow_sectionrUrrrCrErewarning)rhrJ has_new_staterrQrRr'infor0r0r5rds*z*ConfigurableTicketWorkflow.get_all_actionscsfdd|jD}|S)zsReturn a list of all actions with a given operation (for use in the controller's get_all_status()) cs(g|]\}}|dvr|d|fqS)r*r)r0r3rOrrr0r5r6s  zGConfigurableTicketWorkflow.get_actions_by_operation..)rJrC)rhrrJr0rr5get_actions_by_operations z3ConfigurableTicketWorkflow.get_actions_by_operationcs6jddfddjD}|S)zReturn list of all actions with a given operation that are valid in the given state for the controller's get_ticket_actions(). If state='*' (the default), all actions with the given operation are returned. rrcsPg|]$\}}|dvr&d|dvs|dvr|jr|d|fqS)r*r r%r))ryrxrrr}rhrrr~r0r5r6s    zOConfigurableTicketWorkflow.get_actions_by_operation_for_req..)rvrwrJrC)rhr}r~rrJr0rr5 get_actions_by_operation_for_reqs z;ConfigurableTicketWorkflow.get_actions_by_operation_for_reqcs`d|vr ||d|St|jjr.t|jd}tt|j|jdt fdd|DSdS)aPReturns users listed in the `set_owner` field of the action or possessing the `TICKET_MODIFY` permission if `set_owner` is not specified. This method can be overridden in a subclasses in order to customize the list of users that populate the assign-to select box. :since: 1.3.2 r, TICKET_MODIFYrc3s"|] }d|dvr|VqdS)r)usernameNr0r3ucacher0r5rs z@ConfigurableTicketWorkflow.get_allowed_owners..N) _to_usersrr{restrict_ownerr get_users_with_permissionrr rxr)rhr}r~rOusersr0rr5rs  z-ConfigurableTicketWorkflow.get_allowed_ownerscCsL|dvr$d}|dr"z t|j|d}Wn tyY|Sw|j}|S|S)zbSubstitute keywords from the default_owner field. < default > -> component owner )z < default >z r$r)rr{rrs)rhrsr~rrr0r0r5rs z-ConfigurableTicketWorkflow._sub_owner_keywordcs>tjfddt|tS)zFinds all users contained in the list of `users_perms_and_groups` by recursive lookup of users when a `group` is encountered. cs|D]B}|dkrddjDq|r4|}|D]}|tj|jvr2|q!q|vr>|q|qdS)N authenticatedcSh|]}|dqS)rr0rr0r0r5 0r7zNConfigurableTicketWorkflow._to_users..append_owners..)r:r{get_known_usersisupperrr rxr)users_perms_and_groupsuser_perm_or_groupruser append_ownersgroupsrpsrhr~r0r5r-s    z;ConfigurableTicketWorkflow._to_users..append_owners)r r{get_groups_dictrYr)rhrr~r0rr5r&s z$ConfigurableTicketWorkflow._to_usersN)__name__ __module__ __qualname____doc__ implementsrrrrr*rirlrorqrryr|rrrrdrrrrrr0r0r0r5r]vs0  )  F  r]c@s"eZdZdZedZdddZdS) WorkflowMacromessagesaRender a workflow graph. This macro accepts a TracWorkflow configuration and renders the states and transitions as a directed graph. If no parameters are given, the current ticket workflow is rendered. In [WikiProcessors WikiProcessor] mode the `width` and `height` arguments can be specified (Defaults: `width = 800` and `height = 600`). The repository-scoped path of a workflow file can be specified as either a macro or !WikiProcessor `file` argument. The file revision can be specified by appending `@` to the path. The `file` argument value must be enclosed in single or double quotes. //(Since 1.3.2)//. Examples: {{{ [[Workflow()]] [[Workflow(go = here -> there; return = there -> here)]] [[Workflow(file=/contrib/workflow/enterprise-workflow.ini@1)]] {{{#!Workflow file="/contrib/workflow/enterprise-workflow.ini" }}} {{{#!Workflow width=700 height=700 leave = * -> * leave.operations = leave_status leave.default = 1 create = -> new create.default = 1 create_and_assign = -> assigned create_and_assign.label = assign create_and_assign.permissions = TICKET_MODIFY create_and_assign.operations = may_set_owner accept = new,assigned,accepted,reopened -> accepted accept.permissions = TICKET_MODIFY accept.operations = set_owner_to_self resolve = new,assigned,accepted,reopened -> closed resolve.permissions = TICKET_MODIFY resolve.operations = set_resolution reassign = new,assigned,accepted,reopened -> assigned reassign.permissions = TICKET_MODIFY reassign.operations = set_owner reopen = closed -> reopened reopen.permissions = TICKET_CREATE reopen.operations = del_resolution }}} }}} Nc Csl|dur|}|s|s|jd}n|du}|r%t|d}|d}n |d}|s2|s2td|rPt|t|j |} | durOtt dt |dn|r`d dd |d D} n|} d | vrjd | } t} z | t| Wnty} z|rtt| | tt| | d} ~ wwt| d}t|} td d| Ddd| DB} dd| D}t| }g}| D]$\}}| |d}||}|dD]}| |}||||fqq|pi}|dd}|dd}| ||||d}dt|}|j}t|dt|d||it t j ddd|d||fd t !t j t"d!d"d#S)$NrTr/filezInvalid argument(s).z!The file %(file)s does not exist.)r css|]}|VqdSrn)lstrip)r3liner0r0r5rrz-WorkflowMacro.expand_macro..;z[ticket-workflow]z[ticket-workflow] cSsh|] }|dD]}|qqS)r%r0)r3rOstater0r0r5rs  z-WorkflowMacro.expand_macro..cSr)r&r0)r3rOr0r0r5rr7cSsg|]}|dqS)r(r0)r3attrsr0r0r5r6r7z.WorkflowMacro.expand_macro..r&r%widthi heightiX)nodesrJedgesrrz%012xzcommon/js/workflow_graph.jszgraph_%sr$z!trac-workflow-graph trac-noscriptztrac-workflow-graph-%sz+display:inline-block;width:%spx;height:%spx)class_rstylez0Enable JavaScript to display the workflow graph.zsystem-message)r)#r1rVrUr#rwr!printrr{read_file_by_pathrrcodejoinr<rreadfpioStringIOrr rrBrCrSrindexrzrr}rrdivnoscriptr)rh formatterr'contentrrWis_macrokwargsrrparsererJstates action_labels action_namesrrO new_index name_index old_state old_indexrrgraphgraph_idr}r0r0r5 expand_macro~s           zWorkflowMacro.expand_macrorn)rrr_domainr _descriptionrr0r0r0r5rBs :r);r configparserrr collectionsr functoolsr pkg_resourcesrtrac.apir trac.configrr r trac.core trac.permr r trac.resourcertrac.ticket.apirrtrac.ticket.modelrrr trac.utilrrrrtrac.util.htmlrtrac.util.presentationrtrac.util.translationrrrtrac.versioncontrol.apirtrac.web.chromerrrtrac.wiki.formatterr r!trac.wiki.macrosr"r#rSrXr\r]rr0r0r0r5s8        7  O