Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/TracWorkflow URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/TracWorkflow?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/TracWorkflow (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/TracWorkflow Sat Nov 15 01:14:46 2014 @@ -1,7 +1,7 @@ = The Trac Ticket Workflow System = [[TracGuideToc]] -The Trac issue database provides a configurable workflow. +The Trac ticket system provides a configurable workflow. == The Default Ticket Workflow == === Environments upgraded from 0.10 === @@ -58,7 +58,7 @@ reopen.operations = del_resolution There are several example workflows provided in the Trac source tree; look in [trac:source:trunk/contrib/workflow contrib/workflow] for `.ini` config sections. One of those may be a good match for what you want. They can be pasted into the `[ticket-workflow]` section of your `trac.ini` file. However if you have existing tickets then there may be issues if those tickets have states that are not in the new workflow. -Here are some [http://trac.edgewall.org/wiki/WorkFlow/Examples diagrams] of the above examples. +Here are some [trac:WorkFlow/Examples diagrams] of the above examples. == Basic Ticket Workflow Customization == @@ -67,7 +67,7 @@ Note: Ticket "statuses" or "states" are Create a `[ticket-workflow]` section in `trac.ini`. Within this section, each entry is an action that may be taken on a ticket. For example, consider the `accept` action from `simple-workflow.ini`: -{{{ +{{{#!ini accept = new,accepted -> accepted accept.permissions = TICKET_MODIFY accept.operations = set_owner_to_self @@ -77,34 +77,34 @@ The `accept.permissions` line specifies The `accept.operations` line specifies changes that will be made to the ticket in addition to the status change when this action is taken. In this case, when a user clicks on `accept`, the ticket owner field is updated to the logged in user. Multiple operations may be specified in a comma separated list. The available operations are: - - del_owner -- Clear the owner field. - - set_owner -- Sets the owner to the selected or entered owner. - - ''actionname''`.set_owner` may optionally be set to a comma delimited list or a single value. - - set_owner_to_self -- Sets the owner to the logged in user. - - del_resolution -- Clears the resolution field - - set_resolution -- Sets the resolution to the selected value. - - ''actionname''`.set_resolution` may optionally be set to a comma delimited list or a single value. Example: - {{{ +- **del_owner** -- Clear the owner field. +- **set_owner** -- Sets the owner to the selected or entered owner. Defaults to the current user. When `[ticket] restrict_owner = true`, the select will be populated with users that have `TICKET_MODIFY` permission and an authenticated session. + - ''actionname''`.set_owner` may optionally be set to a comma delimited list of users that will be used to populate the select, or a single user. +- **set_owner_to_self** -- Sets the owner to the logged in user. +- **del_resolution** -- Clears the resolution field +- **set_resolution** -- Sets the resolution to the selected value. + - ''actionname''`.set_resolution` may optionally be set to a comma delimited list or a single value. Example: + {{{#!ini resolve_new = new -> closed resolve_new.name = resolve resolve_new.operations = set_resolution resolve_new.permissions = TICKET_MODIFY resolve_new.set_resolution = invalid,wontfix - }}} - - leave_status -- Displays "leave as <current status>" and makes no change to the ticket. +}}} +- **leave_status** -- Displays "leave as <current status>" and makes no change to the ticket. '''Note:''' Specifying conflicting operations (such as `set_owner` and `del_owner`) has unspecified results. -{{{ +In this example, we see the `.name` attribute used. The action here is `resolve_accepted`, but it will be presented to the user as `resolve`. + +{{{#!ini resolve_accepted = accepted -> closed resolve_accepted.name = resolve resolve_accepted.permissions = TICKET_MODIFY resolve_accepted.operations = set_resolution }}} -In this example, we see the `.name` attribute used. The action here is `resolve_accepted`, but it will be presented to the user as `resolve`. - For actions that should be available in all states, `*` may be used in place of the state. The obvious example is the `leave` action: -{{{ +{{{#!ini leave = * -> * leave.operations = leave_status leave.default = 1 @@ -114,24 +114,22 @@ If not specified for an action, `.defaul There are a couple of hard-coded constraints to the workflow. In particular, tickets are created with status `new`, and tickets are expected to have a `closed` state. Further, the default reports/queries treat any state other than `closed` as an open state. -While creating or modifying a ticket workflow, `contrib/workflow/workflow_parser.py` may be useful. It can create `.dot` files that [http://www.graphviz.org GraphViz] understands to provide a visual description of the workflow. +Workflows can be visualized by rendering them on the wiki using the [WikiMacros#Workflow-macro Workflow macro]. -This can be done as follows (your install path may be different). -{{{ +Workflows can also be visualized using the `contrib/workflow/workflow_parser.py` script. The script outputs `.dot` files that [http://www.graphviz.org GraphViz] understands. The script can be used as follows (your install path may be different): +{{{#!sh cd /var/local/trac_devel/contrib/workflow/ sudo ./showworkflow /srv/trac/PlannerSuite/conf/trac.ini }}} And then open up the resulting `trac.pdf` file created by the script (it will be in the same directory as the `trac.ini` file). -An online copy of the workflow parser is available at http://foss.wush.net/cgi-bin/visual-workflow.pl - After you have changed a workflow, you need to restart apache for the changes to take effect. This is important, because the changes will still show up when you run your script, but all the old workflow steps will still be there until the server is restarted. == Example: Adding optional Testing with Workflow == By adding the following to your [ticket-workflow] section of trac.ini you get optional testing. When the ticket is in new, accepted or needs_work status you can choose to submit it for testing. When it's in the testing status the user gets the option to reject it and send it back to needs_work, or pass the testing and send it along to closed. If they accept it then it gets automatically marked as closed and the resolution is set to fixed. Since all the old work flow remains, a ticket can skip this entire section. -{{{ +{{{#!ini testing = new,accepted,needs_work,assigned,reopened -> testing testing.name = Submit to reporter for testing testing.permissions = TICKET_MODIFY @@ -161,7 +159,7 @@ Sometimes Trac is used in situations whe The new `reviewing` state along with its associated `review` action looks like this: -{{{ +{{{#!ini review = new,assigned,reopened -> reviewing review.operations = set_owner review.permissions = TICKET_MODIFY @@ -169,7 +167,7 @@ review.permissions = TICKET_MODIFY Then, to integrate this with the default Trac 0.11 workflow, you also need to add the `reviewing` state to the `accept` and `resolve` actions, like so: -{{{ +{{{#!ini accept = new,reviewing -> assigned [â¦] resolve = new,assigned,reopened,reviewing -> closed @@ -177,7 +175,7 @@ resolve = new,assigned,reopened,reviewin Optionally, you can also add a new action that allows you to change the ticket's owner without moving the ticket out of the `reviewing` state. This enables you to reassign review work without pushing the ticket back to the `new` status. -{{{ +{{{#!ini reassign_reviewing = reviewing -> * reassign_reviewing.name = reassign review reassign_reviewing.operations = set_owner @@ -186,7 +184,7 @@ reassign_reviewing.permissions = TICKET_ The full `[ticket-workflow]` configuration will thus look like this: -{{{ +{{{#!ini [ticket-workflow] accept = new,reviewing -> assigned accept.operations = set_owner_to_self @@ -214,9 +212,9 @@ reassign_reviewing.permissions = TICKET_ == Example: Limit the resolution options for a new ticket == -The above resolve_new operation allows you to set the possible resolutions for a new ticket. By modifying the existing resolve action and removing the new status from before the `->` we then get two resolve actions. One with limited resolutions for new tickets, and then the regular one once a ticket is accepted. +The above `resolve_new` operation allows you to set the possible resolutions for a new ticket. By modifying the existing resolve action and removing the new status from before the `->` we then get two resolve actions. One with limited resolutions for new tickets, and then the regular one once a ticket is accepted. -{{{ +{{{#!ini resolve_new = new -> closed resolve_new.name = resolve resolve_new.operations = set_resolution @@ -238,32 +236,6 @@ But if even that is not enough, you can If you add additional states to your workflow, you may want to customize your milestone progress bars as well. See [TracIni#milestone-groups-section TracIni]. -== some ideas for next steps == - -New enhancement ideas for the workflow system should be filed as enhancement tickets against the `ticket system` component. If desired, add a single-line link to that ticket here. Also look at the [http://trac-hacks.org/wiki/AdvancedTicketWorkflowPlugin AdvancedTicketWorkflowPlugin] as it provides experimental operations. - -If you have a response to the comments below, create an enhancement ticket, and replace the description below with a link to the ticket. - - * the "operation" could be on the nodes, possible operations are: - * '''preops''': automatic, before entering the state/activity - * '''postops''': automatic, when leaving the state/activity - * '''actions''': can be chosen by the owner in the list at the bottom, and/or drop-down/pop-up together with the default actions of leaving the node on one of the arrows. -''This appears to add complexity without adding functionality; please provide a detailed example where these additions allow something currently impossible to implement.'' - - * operations could be anything: sum up the time used for the activity, or just write some statistical fields like -''A workflow plugin can add an arbitrary workflow operation, so this is already possible.'' - - * set_actor should be an operation allowing to set the owner, e.g. as a "preop": - * either to a role, a person - * entered fix at define time, or at run time, e.g. out of a field, or select. -''This is either duplicating the existing `set_owner` operation, or needs to be clarified.'' - - * Actions should be selectable based on the ticket type (different Workflows for different tickets) -''Look into the [http://trac-hacks.org/wiki/AdvancedTicketWorkflowPlugin AdvancedTicketWorkflowPlugin]'s `triage` operation.'' - - * I'd wish to have an option to perform automatic status changes. In my case, I do not want to start with "new", but with "assigned". So tickets in state "new" should automatically go into state "assigned". Or is there already a way to do this and I just missed it? -''Have a look at [http://trac-hacks.org/wiki/TicketCreationStatusPlugin TicketCreationStatusPlugin] and [http://trac-hacks.org/wiki/TicketConditionalCreationStatusPlugin TicketConditionalCreationStatusPlugin]'' - - * I added a 'testing' state. A tester can close the ticket or reject it. I'd like the transition from testing to rejected to set the owner to the person that put the ticket in 'testing'. The [http://trac-hacks.org/wiki/AdvancedTicketWorkflowPlugin AdvancedTicketWorkflowPlugin] is close with set_owner_to_field, but we need something like set_field_to_owner. +== Ideas for next steps == - * I'd like to track the time a ticket is in each state, adding up 'disjoints' intervals in the same state. +New enhancement ideas for the workflow system should be filed as enhancement tickets against the `ticket system` component. You can also document ideas on the [trac:TracIdeas/TracWorkflow TracIdeas/TracWorkflow] page. Also look at the [http://trac-hacks.org/wiki/AdvancedTicketWorkflowPlugin AdvancedTicketWorkflowPlugin] as it provides experimental operations.
Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/WikiFormatting URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/WikiFormatting?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/WikiFormatting (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/WikiFormatting Sat Nov 15 01:14:46 2014 @@ -263,6 +263,7 @@ The Trac wiki supports the following fon * ,,subscript,, * **also bold**, //italic as well//, and **'' bold italic **'' //(since 0.12)// + * [[span(style=color: #FF0000, a red text )]] }}} }}} {{{#!td @@ -280,6 +281,7 @@ The Trac wiki supports the following fon * ,,subscript,, * **also bold**, //italic as well//, and **'' bold italic **'' //(since 0.12)// + * [[span(style=color: #FF0000, a red text )]] }}} Notes: @@ -736,9 +738,9 @@ You may avoid making hyperlinks out of T }}} {{{ Various forms of escaping for list markup: - `-` escaped minus sign \\ - ``1. escaped number \\ - {{{*}}} escaped asterisk sign + ^^- escaped minus sign \\ + ^^1. escaped number \\ + ^^* escaped asterisk sign }}} }}} {{{#!td @@ -746,9 +748,9 @@ Various forms of escaping for list marku !#42 is not a link Various forms of escaping for list markup: - `-` escaped minus sign \\ - ``1. escaped number \\ - {{{*}}} escaped asterisk sign + ^^- escaped minus sign \\ + ^^1. escaped number \\ + ^^* escaped asterisk sign }}} == Images == @@ -1004,4 +1006,3 @@ See? {{{#!td !WikiCreole style \\ line\\break }}} - Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/WikiMacros URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/WikiMacros?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/WikiMacros (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/WikiMacros Sat Nov 15 01:14:46 2014 @@ -101,7 +101,7 @@ class TimeStampMacro(WikiMacroBase): def expand_macro(self, formatter, name, text): t = datetime.now(utc) - return tag.b(format_datetime(t, '%c')) + return tag.strong(format_datetime(t, '%c')) }}} === Macro with arguments === Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/WikiNewPage URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/WikiNewPage?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/WikiNewPage (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/WikiNewPage Sat Nov 15 01:14:46 2014 @@ -3,14 +3,14 @@ Note: make sure you actually have the rights to edit wiki pages. If you don't see the **Edit this page** button, read the information relative to the editing policy for your Trac installation (usually on the front page WikiStart), or contact your local Trac administrator. +You can create a new wiki page by typing the CamelCase name of the page in the quick-search field at the top of the page, or by trying to view a wiki page of that name (That is by visiting http://trac.edgewall.org/wiki/MyNewWikiPage for example). But note that the page will effectively be "orphaned" unless you link to it from somewhere else. Alternatively: + 1. Choose a name for your new page. See WikiPageNames for naming conventions. 2. Edit an existing page (or any other resources that support WikiFormatting and add a [TracLinks link] to your new page. Save your changes. 3. Follow the link you created to take you to the new page. Trac will display a "describe !PageName here" message. 4. Click the "Edit this page" button to edit and add content to your new page. Save your changes. 5. All done. Your new page is published. -You can skip the second step by entering the CamelCase name of the page in the quick-search field at the top of the page. But note that the page will effectively be "orphaned" unless you link to it from somewhere else. - == Rename a page #renaming While picking up good WikiPageNames is important, you can always change your mind Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/WikiProcessors URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/WikiProcessors?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/WikiProcessors (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/WikiProcessors Sat Nov 15 01:14:46 2014 @@ -155,8 +155,9 @@ The following processors are included in || '''`#!default`''' || Present the text verbatim in a preformatted text block. This is the same as specifying ''no'' processor name (and no `#!`) || || '''`#!comment`''' || Do not process the text in this section (i.e. contents exist only in the plain text - not in the rendered page). || +|| '''`#!rtl`''' || Introduce a Right-To-Left block with appropriate CSS direction and styling ''(since 0.12.2)'' || |||| || -||||= '''HTML related''' =|| +||||= '''[=#HTMLrelated HTML related]''' =|| || '''`#!html`''' || Insert custom HTML in a wiki page. || || '''`#!htmlcomment`''' || Insert an HTML comment in a wiki page (''since 0.12''). || || || Note that `#!html` blocks have to be ''self-contained'', i.e. you can't start an HTML element in one block and close it later in a second block. Use the following processors for achieving a similar effect. || @@ -164,14 +165,15 @@ The following processors are included in || '''`#!span`''' || Wrap an arbitrary Wiki content inside a <span> element (''since 0.11''). || || '''`#!td`''' || Wrap an arbitrary Wiki content inside a <td> element (''since 0.12'') || || '''`#!th`''' || Wrap an arbitrary Wiki content inside a <th> element (''since 0.12'') || -|| '''`#!tr`''' || Can optionally be used for wrapping `#!td` and `#!th` blocks, either for specifying row attributes of better visual grouping (''since 0.12'') || +|| '''`#!tr`''' || Can optionally be used for wrapping `#!td` and `#!th` blocks, either for specifying row attributes or better visual grouping (''since 0.12'') || +|| '''`#!table`''' || Can optionally be used for wrapping `#!tr`, `#!td` and `#!th` blocks, for specifying table attributes. One current limitation however is that tables cannot be nested. (''since 0.12'') || || || See WikiHtml for example usage and more details about these processors. || |||| || ||||= '''Other Markups''' =|| || '''`#!rst`''' || Trac support for Restructured Text. See WikiRestructuredText. || || '''`#!textile`''' || Supported if [http://cheeseshop.python.org/pypi/textile Textile] is installed. See [http://www.textism.com/tools/textile/ a Textile reference]. || |||| || -||||= '''Code Highlighting Support''' =|| +||||= '''[=#CodeHighlightingSupport Code Highlighting Support]''' =|| || '''`#!c`''' [[BR]] '''`#!cpp`''' (C++) [[BR]] '''`#!python`''' [[BR]] '''`#!perl`''' [[BR]] '''`#!ruby`''' [[BR]] '''`#!php`''' [[BR]] '''`#!asp`''' [[BR]] '''`#!java`''' [[BR]] '''`#!js`''' (Javascript) [[BR]] '''`#!sql`''' [[BR]] '''`#!xml`''' (XML or HTML) [[BR]] '''`#!sh`''' (!Bourne/Bash shell) [[BR]] '''etc.''' [[BR]] || Trac includes processors to provide inline syntax highlighting for source code in various languages. [[BR]] [[BR]] Trac relies on external software packages for syntax coloring, like [http://pygments.org Pygments]. [[BR]] [[BR]] See TracSyntaxColoring for information about which languages are supported and how to enable support for more languages. || |||| || Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/WikiStart URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/WikiStart?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/WikiStart (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/default-pages/WikiStart Sat Nov 15 01:14:46 2014 @@ -1,4 +1,4 @@ -= Welcome to Trac 1.0.1 = += Welcome to Trac 1.0.2 = Trac is a '''minimalistic''' approach to '''web-based''' management of '''software projects'''. Its goal is to simplify effective tracking and handling of software issues, enhancements and overall progress. Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/formatter.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/formatter.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/formatter.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/formatter.py Sat Nov 15 01:14:46 2014 @@ -35,7 +35,7 @@ from trac.util import arity from trac.util.text import exception_to_unicode, shorten_line, to_unicode, \ unicode_quote, unicode_quote_plus, unquote_label from trac.util.html import TracHTMLSanitizer -from trac.util.translation import _ +from trac.util.translation import _, tag_ from trac.wiki.api import WikiSystem, parse_args from trac.wiki.parser import WikiParser, parse_processor_args @@ -69,7 +69,8 @@ def split_url_into_path_query_fragment(t idx = target.find('?') if idx >= 0: target, query = target[:idx], target[idx:] - return (target, query, fragment) + return target, query, fragment + def concat_path_query_fragment(path, query, fragment=None): """Assemble `path`, `query` and `fragment` into a proper URL. @@ -97,6 +98,7 @@ def concat_path_query_fragment(path, que f = fragment return p + q + ('' if f == '#' else f) + def _markup_to_unicode(markup): stream = None if isinstance(markup, Element): @@ -150,9 +152,9 @@ class WikiProcessor(object): } self.inline_check = {'html': self._html_is_inline, - 'htmlcomment': True, 'comment': True, - 'span': True, 'Span': True, - }.get(name) + 'htmlcomment': True, 'comment': True, + 'span': True, 'Span': True, + }.get(name) self._sanitizer = TracHTMLSanitizer(formatter.wiki.safe_schemes) @@ -172,7 +174,6 @@ class WikiProcessor(object): break if not self.processor: # Find a matching mimeview renderer - from trac.mimeview.api import Mimeview mimeview = Mimeview(formatter.env) for renderer in mimeview.renderers: if renderer.get_quality_ratio(self.name) > 1: @@ -185,7 +186,8 @@ class WikiProcessor(object): self.processor = self._mimeview_processor if not self.processor: self.processor = self._default_processor - self.error = "No macro or processor named '%s' found" % name + self.error = _("No macro or processor named '%(name)s' found", + name=name) # inline checks @@ -349,8 +351,8 @@ class WikiProcessor(object): def process(self, text, in_paragraph=False): if self.error: - text = system_message(tag('Error: Failed to load processor ', - tag.code(self.name)), + text = system_message(tag_("Error: Failed to load processor " + "%(name)s", name=tag.code(self.name)), self.error) else: text = self.processor(text) @@ -438,7 +440,7 @@ class Formatter(object): 'MM_STRIKE': ('<del>', '</del>'), 'MM_SUBSCRIPT': ('<sub>', '</sub>'), 'MM_SUPERSCRIPT': ('<sup>', '</sup>'), - } + } def _get_open_tag(self, tag): """Retrieve opening tag for direct or indirect `tag`.""" @@ -477,12 +479,12 @@ class Formatter(object): If `close_tag` is not specified, it's an indirect tag (0.12) """ - tmp = '' + tmp = '' for i in xrange(len(self._open_tags) - 1, -1, -1): tag = self._open_tags[i] tmp += self._get_close_tag(tag) if (open_tag == tag, - (open_tag, close_tag) == tag)[bool(close_tag)]: + (open_tag, close_tag) == tag)[bool(close_tag)]: del self._open_tags[i] for j in xrange(i, len(self._open_tags)): tmp += self._get_open_tag(self._open_tags[j]) @@ -491,21 +493,42 @@ class Formatter(object): def _indirect_tag_handler(self, match, tag): """Handle binary inline style tags (indirect way, 0.12)""" + if self._list_stack and not self.in_list_item: + self.close_list() + if self.tag_open_p(tag): return self.close_tag(tag) else: return self.open_tag(tag) def _bolditalic_formatter(self, match, fullmatch): + if self._list_stack and not self.in_list_item: + self.close_list() + + bold_open = self.tag_open_p('MM_BOLD') italic_open = self.tag_open_p('MM_ITALIC') - tmp = '' - if italic_open: - tmp += self._get_close_tag('MM_ITALIC') - self.close_tag('MM_ITALIC') - tmp += self._bold_formatter(match, fullmatch) - if not italic_open: - tmp += self.open_tag('MM_ITALIC') - return tmp + if bold_open and italic_open: + bold_idx = self._open_tags.index('MM_BOLD') + italic_idx = self._open_tags.index('MM_ITALIC') + if italic_idx < bold_idx: + close_tags = ('MM_BOLD', 'MM_ITALIC') + else: + close_tags = ('MM_ITALIC', 'MM_BOLD') + open_tags = () + elif bold_open: + close_tags = ('MM_BOLD',) + open_tags = ('MM_ITALIC',) + elif italic_open: + close_tags = ('MM_ITALIC',) + open_tags = ('MM_BOLD',) + else: + close_tags = () + open_tags = ('MM_BOLD', 'MM_ITALIC') + + tmp = [] + tmp.extend(self.close_tag(tag) for tag in close_tags) + tmp.extend(self.open_tag(tag) for tag in open_tags) + return ''.join(tmp) def _bold_formatter(self, match, fullmatch): return self._indirect_tag_handler(match, 'MM_BOLD') @@ -549,7 +572,7 @@ class Formatter(object): # -- Post- IWikiSyntaxProvider rules - # WikiCreole line brekas + # WikiCreole line breaks def _linebreak_wc_formatter(self, match, fullmatch): return '<br />' @@ -575,7 +598,7 @@ class Formatter(object): ns = fullmatch.group('snsbr') target = unquote_label(fullmatch.group('stgtbr')) match = match[1:-1] - return '<%s>' % \ + return u'<%s>' % \ self._make_link(ns, target, match, match, fullmatch) def _shref_formatter(self, match, fullmatch): @@ -764,10 +787,10 @@ class Formatter(object): try: return macro.ensure_inline(macro.process(args)) except Exception, e: - self.env.log.error('Macro %s(%s) failed: %s' % - (name, args, exception_to_unicode(e, traceback=True))) - return system_message('Error: Macro %s(%s) failed' % (name, args), - e) + self.env.log.error('Macro %s(%s) failed:%s', name, args, + exception_to_unicode(e, traceback=True)) + return system_message(_("Error: Macro %(name)s(%(args)s) failed", + name=name, args=args), to_unicode(e)) # Headings @@ -1005,7 +1028,7 @@ class Formatter(object): if separator[-1] == '=': numpipes -= 1 cell = 'th' - colspan = numpipes/2 + colspan = numpipes / 2 if is_last is not None: if is_last and is_last[-1] == '\\': self.continue_table_row = 1 @@ -1131,7 +1154,8 @@ class Formatter(object): for l in self.code_buf] self.code_buf.append('') code_text = os.linesep.join(self.code_buf) - processed = self.code_processor.process(code_text) + processed = self._exec_processor(self.code_processor, + code_text) self.out.write(_markup_to_unicode(processed)) else: self.code_buf.append(line) @@ -1152,6 +1176,15 @@ class Formatter(object): while self.in_code_block > 0: self.handle_code_block(WikiParser.ENDBLOCK) + def _exec_processor(self, processor, text): + try: + return processor.process(text) + except Exception, e: + self.env.log.error('Processor %s failed:%s', processor.name, + exception_to_unicode(e, traceback=True)) + return system_message(_("Error: Processor %(name)s failed", + name=processor.name), to_unicode(e)) + # > quotes def handle_quote_block(self, line): @@ -1505,7 +1538,7 @@ class HtmlFormatter(object): class InlineHtmlFormatter(object): """Format parsed wiki text to inline elements HTML. - Block level content will be disguarded or compacted. + Block level content will be discarded or compacted. """ flavor = 'oneliner' Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/intertrac.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/intertrac.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/intertrac.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/intertrac.py Sat Nov 15 01:14:46 2014 @@ -20,9 +20,8 @@ from genshi.builder import Element, Frag from trac.config import ConfigSection from trac.core import * -from trac.perm import PermissionError from trac.util.html import find_element -from trac.util.translation import _, N_ +from trac.util.translation import N_, _, tag_ from trac.web.api import IRequestHandler from trac.wiki.api import IWikiMacroProvider from trac.wiki.formatter import extract_link @@ -53,7 +52,7 @@ class InterTracDispatcher(Component): it doesn't know how to dispatch an InterTrac link, and it's up to the local Trac to prepare the correct link. Not all links will work that way, but the most common do. This is called the compatibility - mode, and is `true` by default. + mode, and is `false` by default. * If you know that the remote Trac knows how to dispatch InterTrac links, you can explicitly disable this compatibility mode and then ''any'' TracLinks can become InterTrac links. @@ -90,8 +89,10 @@ class InterTracDispatcher(Component): link_frag = extract_link(self.env, web_context(req), link) if isinstance(link_frag, (Element, Fragment)): elt = find_element(link_frag, 'href') - if elt is None: # most probably no permissions to view - raise PermissionError(_("Can't view %(link)s:", link=link)) + if elt is None: + raise TracError( + _("Can't view %(link)s. Resource doesn't exist or " + "you don't have the required permission.", link=link)) href = elt.attrib.get('href') else: href = req.href(link.rstrip(':')) @@ -122,16 +123,18 @@ class InterTracDispatcher(Component): def generate_prefix(prefix): intertrac = intertracs[prefix] if isinstance(intertrac, basestring): - yield tag.tr(tag.td(tag.b(prefix)), - tag.td('Alias for ', tag.b(intertrac))) + yield tag.tr(tag.td(tag.strong(prefix)), + tag.td(tag_("Alias for %(name)s", + name=tag.strong(intertrac)))) else: url = intertrac.get('url', '') if url: title = intertrac.get('title', url) - yield tag.tr(tag.td(tag.a(tag.b(prefix), + yield tag.tr(tag.td(tag.a(tag.strong(prefix), href=url + '/timeline')), tag.td(tag.a(title, href=url))) return tag.table(class_="wiki intertrac")( - tag.tr(tag.th(tag.em('Prefix')), tag.th(tag.em('Trac Site'))), + tag.tr(tag.th(tag.em(_("Prefix"))), + tag.th(tag.em(_("Trac Site")))), [generate_prefix(p) for p in sorted(intertracs.keys())]) Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/interwiki.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/interwiki.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/interwiki.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/interwiki.py Sat Nov 15 01:14:46 2014 @@ -172,8 +172,8 @@ class InterWikiMap(Component): 'rc_url': self._expand_or_append(url, ['RecentChanges']), 'description': url if title == prefix else title}) - return tag.table(tag.tr(tag.th(tag.em("Prefix")), - tag.th(tag.em("Site"))), + return tag.table(tag.tr(tag.th(tag.em(_("Prefix"))), + tag.th(tag.em(_("Site")))), [tag.tr(tag.td(tag.a(w['prefix'], href=w['rc_url'])), tag.td(tag.a(w['description'], href=w['url']))) Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/macros.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/macros.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/macros.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/macros.py Sat Nov 15 01:14:46 2014 @@ -14,6 +14,8 @@ # # Author: Christopher Lenz <cml...@gmx.de> +from __future__ import with_statement + from fnmatch import fnmatchcase from itertools import groupby import inspect @@ -71,7 +73,7 @@ class WikiMacroBase(Component): def parse_macro(self, parser, name, content): raise NotImplementedError - def expand_macro(self, formatter, name, content): + def expand_macro(self, formatter, name, content, args=None): raise NotImplementedError( "pre-0.11 Wiki macro %s by provider %s no longer supported" % (name, self.__class__)) @@ -327,8 +329,9 @@ class RecentChangesMacro(WikiMacroBase): max(time) AS max_time FROM wiki""" args = [] if prefix: - sql += " WHERE name LIKE %s" - args.append(prefix + '%') + with self.env.db_query as db: + sql += " WHERE name %s" % db.prefix_match() + args.append(db.prefix_match_value(prefix)) sql += " GROUP BY name ORDER BY max_time DESC" if limit: sql += " LIMIT %s" @@ -355,8 +358,9 @@ class RecentChangesMacro(WikiMacroBase): items_per_date = ( (date, (tag.li(tag.a(page, href=formatter.href.wiki(name)), - tag.small(' (', tag.a('diff', href=diff_href), ')') - if diff_href else None, '\n') + tag.small(' (', tag.a(_("diff"), href=diff_href), + ')') if diff_href else None, + '\n') for page, name, version, diff_href in entries)) for date, entries in entries_per_date) @@ -477,21 +481,22 @@ class ImageMacro(WikiMacroBase): Examples: {{{ - [[Image(photo.jpg)]] # simplest - [[Image(photo.jpg, 120px)]] # with image width size - [[Image(photo.jpg, right)]] # aligned by keyword - [[Image(photo.jpg, nolink)]] # without link to source - [[Image(photo.jpg, align=right)]] # aligned by attribute + [[Image(photo.jpg)]] # simplest + [[Image(photo.jpg, 120px)]] # with image width size + [[Image(photo.jpg, right)]] # aligned by keyword + [[Image(photo.jpg, nolink)]] # without link to source + [[Image(photo.jpg, align=right)]] # aligned by attribute }}} - You can use image from other page, other ticket or other module. + You can use an image from a wiki page, ticket or other module. {{{ - [[Image(OtherPage:foo.bmp)]] # if current module is wiki - [[Image(base/sub:bar.bmp)]] # from hierarchical wiki page - [[Image(#3:baz.bmp)]] # if in a ticket, point to #3 - [[Image(ticket:36:boo.jpg)]] - [[Image(source:/images/bee.jpg)]] # straight from the repository! - [[Image(htdocs:foo/bar.png)]] # image file in project htdocs dir. + [[Image(OtherPage:foo.bmp)]] # from a wiki page + [[Image(base/sub:bar.bmp)]] # from hierarchical wiki page + [[Image(#3:baz.bmp)]] # from another ticket + [[Image(ticket:36:boo.jpg)]] # from another ticket (long form) + [[Image(source:/img/bee.jpg)]] # from the repository + [[Image(htdocs:foo/bar.png)]] # from project htdocs dir + [[Image(shared:foo/bar.png)]] # from shared htdocs dir (since 1.0.2) }}} ''Adapted from the Image.py macro created by Shun-ichi Goto @@ -501,6 +506,8 @@ class ImageMacro(WikiMacroBase): def is_inline(self, content): return True + _split_filespec_re = re.compile(r''':(?!(?:[^"':]|[^"']:[^'"])+["'])''') + def expand_macro(self, formatter, name, content): # args will be null if the macro is called without parenthesis. if not content: @@ -534,7 +541,7 @@ class ImageMacro(WikiMacroBase): except Exception: browser_links = [] while args: - arg = args.pop(0).strip() + arg = stripws(args.pop(0)) if size_re.match(arg): # 'width' keyword attr['width'] = arg @@ -578,7 +585,8 @@ class ImageMacro(WikiMacroBase): attr[str(key)] = val # will be used as a __call__ kwd # parse filespec argument to get realm and id if contained. - parts = filespec.split(':') + parts = [i.strip('''['"]''') + for i in self._split_filespec_re.split(filespec)] url = raw_url = desc = None attachment = None if (parts and parts[0] in ('http', 'https', 'ftp')): # absolute @@ -626,6 +634,9 @@ class ImageMacro(WikiMacroBase): elif id == 'htdocs': raw_url = url = formatter.href.chrome('site', filename) desc = os.path.basename(filename) + elif id == 'shared': + raw_url = url = formatter.href.chrome('shared', filename) + desc = os.path.basename(filename) else: realm = 'wiki' if realm: @@ -732,10 +743,10 @@ class TracIniMacro(WikiMacroBase): options whose section and name start with the filters are output. """) - def expand_macro(self, formatter, name, args): + def expand_macro(self, formatter, name, content): from trac.config import ConfigSection, Option section_filter = key_filter = '' - args, kw = parse_args(args) + args, kw = parse_args(content) if args: section_filter = args.pop(0).strip() if args: @@ -761,19 +772,11 @@ class TracIniMacro(WikiMacroBase): def default_cell(option): default = option.default - if default is True: - default = 'true' - elif default is False: - default = 'false' - elif default == 0: - default = '0.0' if isinstance(default, float) else '0' - elif default: - default = ', '.join(to_unicode(val) for val in default) \ - if isinstance(default, (list, tuple)) \ - else to_unicode(default) + if default is not None and default != '': + return tag.td(tag.code(option.dumps(default)), + class_='default') else: return tag.td(_("(no default)"), class_='nodefault') - return tag.td(tag.code(default), class_='default') return tag.div(class_='tracini')( (tag.h3(tag.code('[%s]' % section), id='%s-section' % section), @@ -782,9 +785,11 @@ class TracIniMacro(WikiMacroBase): tag.tr(tag.td(tag.tt(option.name)), tag.td(format_to_oneliner( self.env, formatter.context, getdoc(option))), - default_cell(option)) - for option in sorted(options.get(section, {}).itervalues(), - key=lambda o: o.name) + default_cell(option), + class_='odd' if idx % 2 else 'even') + for idx, option in \ + enumerate(sorted(options.get(section, {}).itervalues(), + key=lambda o: o.name)) if option.name.startswith(key_filter)))) for section, section_doc in sorted(sections.iteritems())) @@ -798,11 +803,11 @@ class KnownMimeTypesMacro(WikiMacroBase) Can be given an optional argument which is interpreted as mime-type filter. """) - def expand_macro(self, formatter, name, args): + def expand_macro(self, formatter, name, content): from trac.mimeview.api import Mimeview mime_map = Mimeview(self.env).mime_map mime_type_filter = '' - args, kw = parse_args(args) + args, kw = parse_args(content) if args: mime_type_filter = args.pop(0).strip().rstrip('*') @@ -865,7 +870,7 @@ class TracGuideTocMacro(WikiMacroBase): ('TracNotification', 'Notification'), ] - def expand_macro(self, formatter, name, args): + def expand_macro(self, formatter, name, content): curpage = formatter.resource.id # scoped TOC (e.g. TranslateRu/TracGuide or 0.11/TracGuide ...) Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/model.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/model.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/model.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/model.py Sat Nov 15 01:14:46 2014 @@ -39,7 +39,7 @@ class WikiPage(object): name = self.resource.id else: if version: - version = int(version) # must be a number or None + version = int(version) # must be a number or None self.resource = Resource('wiki', name, version) self.name = name if name: @@ -84,7 +84,8 @@ class WikiPage(object): :since 1.0: the `db` parameter is no longer needed and will be removed in version 1.1.1 """ - assert self.exists, "Cannot delete non-existent page" + if not self.exists: + raise TracError(_("Cannot delete non-existent page")) with self.env.db_transaction as db: if version is None: @@ -186,9 +187,10 @@ class WikiPage(object): def rename(self, new_name): """Rename wiki page in-place, keeping the history intact. Renaming a page this way will eventually leave dangling references - to the old page - which litterally doesn't exist anymore. + to the old page - which literally doesn't exist anymore. """ - assert self.exists, "Cannot rename non-existent page" + if not self.exists: + raise TracError(_("Cannot rename non-existent page")) if not validate_page_name(new_name): raise TracError(_("Invalid Wiki page name '%(name)s'", @@ -209,8 +211,8 @@ class WikiPage(object): Attachment.reparent_all(self.env, 'wiki', old_name, 'wiki', new_name) - self.name = new_name - self.env.log.info('Renamed page %s to %s', old_name, new_name) + self.name = self.resource.id = new_name + self.env.log.info("Renamed page %s to %s", old_name, new_name) for listener in WikiSystem(self.env).change_listeners: if hasattr(listener, 'wiki_page_renamed'): Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/parser.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/parser.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/parser.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/parser.py Sat Nov 15 01:14:46 2014 @@ -23,6 +23,7 @@ import re from trac.core import * from trac.notification import EMAIL_LOOKALIKE_PATTERN + class WikiParser(Component): """Wiki text parser.""" Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_delete.html URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_delete.html?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_delete.html (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_delete.html Sat Nov 15 01:14:46 2014 @@ -1,3 +1,13 @@ +<!--! Copyright (C) 2006-2014 Edgewall Software + + This software is licensed as described in the file COPYING, which + you should have received as part of this distribution. The terms + are also available at http://trac.edgewall.com/license.html. + + This software consists of voluntary contributions made by many + individuals. For the exact contribution history, see the revision + history and logs, available at http://trac.edgewall.org/. +--> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> @@ -95,10 +105,11 @@ <strong>This is an irreversible operation.</strong> </p> <div class="buttons"> + <input type="submit" class="trac-disable-on-submit" + value="${what == 'multiple' and _('Delete those versions') + or what == 'single' and _('Delete this version') + or _('Delete page')}" /> <input type="submit" name="cancel" value="${_('Cancel')}" /> - <input type="submit" value="${what == 'multiple' and _('Delete those versions') - or what == 'single' and _('Delete this version') - or _('Delete page')}" /> </div> </form> </div> Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_diff.html URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_diff.html?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_diff.html (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_diff.html Sat Nov 15 01:14:46 2014 @@ -1,3 +1,13 @@ +<!--! Copyright (C) 2006-2014 Edgewall Software + + This software is licensed as described in the file COPYING, which + you should have received as part of this distribution. The terms + are also available at http://trac.edgewall.com/license.html. + + This software consists of voluntary contributions made by many + individuals. For the exact contribution history, see the revision + history and logs, available at http://trac.edgewall.org/. +--> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_edit.html URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_edit.html?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_edit.html (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_edit.html Sat Nov 15 01:14:46 2014 @@ -1,3 +1,13 @@ +<!--! Copyright (C) 2006-2014 Edgewall Software + + This software is licensed as described in the file COPYING, which + you should have received as part of this distribution. The terms + are also available at http://trac.edgewall.com/license.html. + + This software consists of voluntary contributions made by many + individuals. For the exact contribution history, see the revision + history and logs, available at http://trac.edgewall.org/. +--> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> @@ -39,9 +49,6 @@ $("#sidebyside").change(function() { $("#edit input[type=submit][name=preview]").click(); }); - <py:if test="not sidebyside and (action == 'preview' or diff)"> - $("#info").scrollToTop(); - </py:if> <py:if test="sidebyside">/*<![CDATA[*/ function editorHeight() { return $("#text").closest("fieldset").innerHeight(); @@ -96,16 +103,6 @@ ↓ </div> <h1 i18n:msg="name">Editing ${name_of(page.resource)}</h1> - <div py:if="merge" class="system-message"> - <p>Someone else has modified that page since you started your edits.</p><br /> - <p i18n:msg=""><b>If you save right away, you risk to revert those changes</b> - (highlighted below as deletions).</p><br /> - <p i18n:msg="">Please review all those changes and manually merge them with your - own changes. <br /> - If you're unsure about what you're doing, please press <tt>Cancel</tt> - (losing your changes) and start editing the latest version of the page - again.</p> - </div> <!--! @@ -131,10 +128,26 @@ (the #preview will float at the right of the edit form's textarea) --> - <py:if test="not sidebyside"><xi:include href="wiki_edit_form.html" /></py:if> <py:choose test="action"> + <py:when test="'collision'"> + <div class="system-message"> + Sorry, this page has been modified by somebody else since you started + editing. Your changes cannot be saved. + </div> + </py:when> + <py:if test="not sidebyside"><xi:include href="wiki_edit_form.html" /></py:if> + <div py:if="merge" class="system-message"> + <p>Someone else has modified that page since you started your edits.</p><br /> + <p i18n:msg=""><strong>If you save right away, you risk to revert those changes</strong> + (highlighted below as deletions).</p><br /> + <p i18n:msg="">Please review all those changes and manually merge them with your + own changes. <br /> + If you're unsure about what you're doing, please press <tt>Cancel</tt> + (losing your changes) and start editing the latest version of the page + again.</p> + </div> <py:when test="'preview'"> - <table id="info" summary="Revision info"> + <table id="info" summary="Revision info" class="${'trac-scroll' if not sidebyside else None}"> <tbody> <tr><th scope="col" i18n:msg="version, author"> Change information for future version ${page.version+1} (modified by $author): @@ -158,7 +171,7 @@ <xi:include href="diff_div.html" py:with="no_id=True" /> </div> <div py:otherwise="" class="wikipage" xml:space="preserve"> - ${wiki_to_html(context.child(page.resource), page.text)} + ${wiki_to_html(context, page.text)} </div> </div> <div py:if="not sidebyside and page.text" class="trac-nav"> @@ -167,12 +180,6 @@ </div> </div> </py:when> - <py:when test="'collision'"> - <div class="system-message"> - Sorry, this page has been modified by somebody else since you started - editing. Your changes cannot be saved. - </div> - </py:when> </py:choose> <py:if test="sidebyside"><xi:include href="wiki_edit_form.html" /></py:if> Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_edit_form.html URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_edit_form.html?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_edit_form.html (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_edit_form.html Sat Nov 15 01:14:46 2014 @@ -1,3 +1,13 @@ +<!--! Copyright (C) 2009-2014 Edgewall Software + + This software is licensed as described in the file COPYING, which + you should have received as part of this distribution. The terms + are also available at http://trac.edgewall.com/license.html. + + This software consists of voluntary contributions made by many + individuals. For the exact contribution history, see the revision + history and logs, available at http://trac.edgewall.org/. +--> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> @@ -26,12 +36,13 @@ </label> <input type="checkbox" name="sidebyside" id="sidebyside" checked="$sidebyside" /> </div> - <p><textarea id="text" class="wikitext${' trac-resizable' if not sidebyside else None}" + <p><textarea id="text" class="${classes('wikitext', 'trac-autofocus', 'trac-fullwidth', + 'trac-resizable' if not sidebyside else None)}" name="text" cols="80" rows="$edit_rows"> $page.text</textarea> </p> <div id="help" i18n:msg=""> - <b>Note:</b> See <a href="${href.wiki('WikiFormatting')}">WikiFormatting</a> and + <strong>Note:</strong> See <a href="${href.wiki('WikiFormatting')}">WikiFormatting</a> and <a href="${href.wiki('TracWiki')}">TracWiki</a> for help on editing wiki content. </div> </fieldset> @@ -43,7 +54,7 @@ $page.text</textarea> <input id="author" type="text" name="author" size="30" value="$author" /> </label> <p py:if="author == 'anonymous'" class="hint"> - <i18n:msg>E-mail address and user name can be saved in the <a href="${href.prefs()}">Preferences</a>.</i18n:msg> + <i18n:msg>E-mail address and user name can be saved in the <a href="${href.prefs()}" class="trac-target-new">Preferences</a>.</i18n:msg> </p> </div> <div class="field"> @@ -68,7 +79,7 @@ $page.text</textarea> <py:otherwise> <input type="submit" name="preview" value="${_('Preview Page')}" accesskey="p" /> <input type="submit" name="diff" value="${_('Review Changes')}" accesskey="r" /> - <input type="submit" id="save" name="save" value="${_('Submit changes')}" /> + <input type="submit" id="save" name="save" class="trac-disable-on-submit" value="${_('Submit changes')}" /> </py:otherwise> <input type="submit" name="cancel" value="${_('Cancel')}" /> </div> Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_page_path.html URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_page_path.html?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_page_path.html (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_page_path.html Sat Nov 15 01:14:46 2014 @@ -1,3 +1,13 @@ +<!--! Copyright (C) 2010-2014 Edgewall Software + + This software is licensed as described in the file COPYING, which + you should have received as part of this distribution. The terms + are also available at http://trac.edgewall.com/license.html. + + This software consists of voluntary contributions made by many + individuals. For the exact contribution history, see the revision + history and logs, available at http://trac.edgewall.org/. +--> <div xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/" xmlns:i18n="http://genshi.edgewall.org/i18n" Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_rename.html URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_rename.html?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_rename.html (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_rename.html Sat Nov 15 01:14:46 2014 @@ -1,3 +1,13 @@ +<!--! Copyright (C) 2010-2014 Edgewall Software + + This software is licensed as described in the file COPYING, which + you should have received as part of this distribution. The terms + are also available at http://trac.edgewall.com/license.html. + + This software consists of voluntary contributions made by many + individuals. For the exact contribution history, see the revision + history and logs, available at http://trac.edgewall.org/. +--> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> @@ -15,22 +25,22 @@ <h1 i18n:msg="name">Rename <a href="$current_href">$page.name</a></h1> <form id="rename-form" action="$current_href" method="post"> <p> - <input type="hidden" name="action" value="rename"/> - <strong>Renaming the page will rename all existing versions of the page in place.</strong><br/> + <input type="hidden" name="action" value="rename" /> + <strong>Renaming the page will rename all existing versions of the page in place.</strong><br /> The complete history of the page will be moved to the new location. </p> <div class="field"> - <label>New name: <input type="text" name="new_name" size="40" value="$new_name"/></label> + <label>New name: <input type="text" name="new_name" class="trac-autofocus" size="40" value="$new_name" /></label> </div> <div class="field"> <label> - <input type="checkbox" id="redirect" name="redirect"/> + <input type="checkbox" id="redirect" name="redirect" /> Leave a redirection page at the old location </label> </div> <div class="buttons"> - <input type="submit" name="cancel" value="${_('Cancel')}"/> - <input type="submit" name="submit" value="${_('Rename page')}"/> + <input type="submit" name="submit" class="trac-disable-on-submit" value="${_('Rename page')}" /> + <input type="submit" name="cancel" value="${_('Cancel')}" /> </div> </form> </div> Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_view.html URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_view.html?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_view.html (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/templates/wiki_view.html Sat Nov 15 01:14:46 2014 @@ -1,3 +1,13 @@ +<!--! Copyright (C) 2006-2014 Edgewall Software + + This software is licensed as described in the file COPYING, which + you should have received as part of this distribution. The terms + are also available at http://trac.edgewall.com/license.html. + + This software consists of voluntary contributions made by many + individuals. For the exact contribution history, see the revision + history and logs, available at http://trac.edgewall.org/. +--> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> @@ -6,6 +16,7 @@ xmlns:i18n="http://genshi.edgewall.org/i18n" xmlns:xi="http://www.w3.org/2001/XInclude" py:with="modify_perm = 'WIKI_MODIFY' in perm(page.resource); + create_perm = 'WIKI_CREATE' in perm(page.resource); admin_perm = 'WIKI_ADMIN' in perm(page.resource); is_not_latest = page.exists and page.version != latest_version"> <xi:include href="layout.html" /> @@ -78,21 +89,21 @@ <py:with vars="delete_perm = 'WIKI_DELETE' in perm(page.resource); rename_perm = 'WIKI_RENAME' in perm(page.resource)"> - <py:if test="admin_perm or (not page.readonly and (modify_perm or delete_perm))"> + <py:if test="admin_perm or (not page.readonly and (modify_perm or create_perm or delete_perm))"> <div class="buttons"> - <py:if test="modify_perm"> + <py:if test="modify_perm or create_perm"> <form method="get" action="${href.wiki(page.name)}" id="modifypage"> <div> <input type="hidden" name="action" value="edit" /> <py:choose> - <py:when test="is_not_latest"> + <py:when test="is_not_latest and modify_perm"> <input type="hidden" name="version" value="${page.version}"/> <input type="submit" value="${_('Revert to this version')}"/> </py:when> - <py:when test="page.exists"> + <py:when test="page.exists and modify_perm"> <input type="submit" value="${_('Edit this page')}" accesskey="e" /> </py:when> - <py:otherwise> + <py:when test="not page.exists and create_perm"> <input type="submit" value="${_('Create this page')}" accesskey="e" /> <div py:if="templates" id="template"> <label for="template">Using the template:</label> @@ -103,7 +114,7 @@ selected="${t == default_template or None}">$t</option> </select> </div> - </py:otherwise> + </py:when> </py:choose> </div> </form> Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/tests/__init__.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/tests/__init__.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/tests/__init__.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/tests/__init__.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2005-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.org/wiki/TracLicense. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/log/. + import doctest import unittest Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/tests/formatter.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/tests/formatter.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/tests/formatter.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/tests/formatter.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2004-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.org/wiki/TracLicense. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/log/. + import difflib import os import re @@ -14,7 +27,7 @@ except ImportError: from datetime import datetime -from trac.core import * +from trac.core import Component, TracError, implements from trac.test import Mock, MockPerm, EnvironmentStub, locale_en from trac.util.datefmt import utc from trac.util.html import html @@ -88,6 +101,14 @@ class WikiProcessorSampleMacro(WikiMacro ''.join('<dt>%s</dt><dd>%s</dd>' % kv for kv in args.items()) \ + content +class ValueErrorWithUtf8Macro(WikiMacroBase): + def expand_macro(self, formatter, name, content, args): + raise ValueError(content.encode('utf-8')) + +class TracErrorWithUnicodeMacro(WikiMacroBase): + def expand_macro(self, formatter, name, content, args): + raise TracError(unicode(content)) + class SampleResolver(Component): """A dummy macro returning a div block, used by the unit test.""" @@ -126,6 +147,7 @@ class WikiTestCase(unittest.TestCase): self._teardown = teardown req = Mock(href=Href('/'), abs_href=Href('http://www.example.com/'), + chrome={}, session={}, authname='anonymous', perm=MockPerm(), tz=utc, args={}, locale=locale_en, lc_time=locale_en) if context: @@ -182,7 +204,7 @@ class WikiTestCase(unittest.TestCase): v = v.replace('\r', '').replace(u'\u200b', '') # FIXME: keep ZWSP v = strip_line_ws(v, leading=False) try: - self.assertEquals(self.correct, v) + self.assertEqual(self.correct, v) except AssertionError, e: msg = to_unicode(e) match = re.match(r"u?'(.*)' != u?'(.*)'", msg) Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/tests/functional.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/tests/functional.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/tests/functional.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/wiki/tests/functional.py Sat Nov 15 01:14:46 2014 @@ -1,22 +1,124 @@ -#!/usr/bin/python +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2008-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.org/wiki/TracLicense. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/log/. + from trac.tests.functional import * from trac.mimeview.rst import has_docutils -from trac.util import get_pkginfo +from trac.util import create_file, get_pkginfo + +try: + from configobj import ConfigObj +except ImportError: + ConfigObj = None + class TestWiki(FunctionalTwillTestCaseSetup): def runTest(self): - """Create a wiki page and attach a file""" - # TODO: this should be split into multiple tests - pagename = random_unique_camel() - self._tester.create_wiki_page(pagename) - self._tester.attach_file_to_wiki(pagename) + """Create a wiki page.""" + self._tester.create_wiki_page() + + +class TestWikiAddAttachment(FunctionalTwillTestCaseSetup): + def runTest(self): + """Add attachment to a wiki page. Test that the attachment + button reads 'Attach file' when no files have been attached, and + 'Attach another file' when there are existing attachments. + Feature added in http://trac.edgewall.org/ticket/10281""" + name = self._tester.create_wiki_page() + self._tester.go_to_wiki(name) + tc.find("Attach file") + filename = self._tester.attach_file_to_wiki(name) + + self._tester.go_to_wiki(name) + tc.find("Attach another file") + tc.find('Attachments <span class="trac-count">\(1\)</span>') + tc.find(filename) + tc.find('Download all attachments as:\s+<a rel="nofollow" ' + 'href="/zip-attachment/wiki/%s/">.zip</a>' % name) + + +class TestWikiPageManipulator(FunctionalTwillTestCaseSetup): + def runTest(self): + plugin_name = self.__class__.__name__ + env = self._testenv.get_trac_environment() + env.config.set('components', plugin_name + '.*', 'enabled') + env.config.save() + create_file(os.path.join(env.path, 'plugins', plugin_name + '.py'), +"""\ +from genshi.builder import tag +from trac.core import Component, implements +from trac.util.translation import tag_ +from trac.wiki.api import IWikiPageManipulator + + +class WikiPageManipulator(Component): + implements(IWikiPageManipulator) + + def prepare_wiki_page(self, req, page, fields): + pass + + def validate_wiki_page(self, req, page): + field = 'comment' + yield None, tag_("The page contains invalid markup at" + " line %(number)s.", number=tag.strong('10')) + yield field, tag_("The field %(field)s cannot be empty.", + field=tag.strong(field)) +""") + self._testenv.restart() + + try: + self._tester.go_to_front() + tc.follow("Wiki") + tc.formvalue('modifypage', 'action', 'edit') + tc.submit() + tc.submit('save', 'edit') + tc.url(self._tester.url + '/wiki/WikiStart$') + tc.find("Invalid Wiki page: The page contains invalid markup at" + " line <strong>10</strong>.") + tc.find("The Wiki page field 'comment' is invalid:" + " The field <strong>comment</strong> cannot be empty.") + finally: + env.config.set('components', plugin_name + '.*', 'disabled') + env.config.save() + + +class TestWikiHistory(FunctionalTwillTestCaseSetup): + """Create wiki page and navigate to page history.""" + def runTest(self): + pagename = self._tester.create_wiki_page() + self._tester.edit_wiki_page(pagename) + tc.follow(r"\bHistory\b") + tc.url(self._tester.url + r'/wiki/%s\?action=history' % pagename) + version_link = '<td class="version">[ \t\n]*' \ + '<a href="/wiki/%(pagename)s\?version=%%(version)s" ' \ + 'title="View this version">%%(version)s[ \t\n]*</a>' \ + % {'pagename': pagename} + tc.find(version_link % {'version': 1}) + tc.find(version_link % {'version': 2}) + tc.formvalue('history', 'old_version', '1') + tc.formvalue('history', 'version', '2') + tc.submit() + tc.url(r'%s/wiki/%s\?action=diff&version=2&old_version=1' + % (self._tester.url, pagename)) + tc.find(r'<a href="/wiki/%s\?version=1">Version 1</a>' % pagename) + tc.find(r'<a href="/wiki/%s\?version=2">Version 2</a>' % pagename) + tc.find(r'<a href="/wiki/%(name)s">%(name)s</a>' % {'name': pagename}) class TestWikiRename(FunctionalTwillTestCaseSetup): def runTest(self): """Test for simple wiki rename""" - pagename = random_unique_camel() - self._tester.create_wiki_page(pagename) + pagename = self._tester.create_wiki_page() attachment = self._tester.attach_file_to_wiki(pagename) base_url = self._tester.url page_url = base_url + "/wiki/" + pagename @@ -60,6 +162,10 @@ class TestWikiRename(FunctionalTwillTest # check redirection page tc.url(page_url) tc.find("See.*/wiki/" + newpagename) + tc.find("The page %s has been renamed to %s." + % (pagename, newpagename)) + tc.find("The page %s has been recreated with a redirect to %s." + % (pagename, newpagename)) # check whether attachment exists on the new page but not on old page tc.go(base_url + '/attachment/wiki/' + newpagename + '/' + attachment) tc.notfind("Error: Invalid Attachment") @@ -73,6 +179,8 @@ class TestWikiRename(FunctionalTwillTest tc.formvalue('rename-form', 'redirect', False) tc.submit('submit') tc.url(base_url + "/wiki/" + newpagename) + tc.find("The page %s has been renamed to %s." + % (pagename, newpagename)) # this time, the original page is gone tc.go(page_url) tc.url(page_url) @@ -91,8 +199,7 @@ class RegressionTestTicket4812(Functiona class ReStructuredTextWikiTest(FunctionalTwillTestCaseSetup): def runTest(self): """Render reStructured text using a wikiprocessor""" - pagename = random_unique_camel() - self._tester.create_wiki_page(pagename, content=""" + pagename = self._tester.create_wiki_page(content=""" {{{ #!rst Hello @@ -112,8 +219,7 @@ Hello class ReStructuredTextCodeBlockTest(FunctionalTwillTestCaseSetup): def runTest(self): """Render reStructured code block""" - pagename = random_unique_camel() - self._tester.create_wiki_page(pagename, content=""" + pagename = self._tester.create_wiki_page(content=""" {{{ #!rst .. code-block:: python @@ -127,6 +233,54 @@ class ReStructuredTextCodeBlockTest(Func tc.find('"123"') +class RegressionTestTicket8976(FunctionalTwillTestCaseSetup): + def runTest(self): + """Test for regression of http://trac.edgewall.org/ticket/8976 + Test fine grained permissions policy on wiki for specific page + versions.""" + name = self._tester.create_wiki_page() + self._tester.edit_wiki_page(name) + self._tester.edit_wiki_page(name) + self._tester.logout() + self._tester.login('user') + try: + self._tester.go_to_wiki(name, 1) + tc.notfind(r"\bError: Forbidden\b") + self._tester.go_to_wiki(name, 2) + tc.notfind(r"\bError: Forbidden\b") + self._tester.go_to_wiki(name, 3) + tc.notfind(r"\bError: Forbidden\b") + self._tester.go_to_wiki(name, 4) + tc.find(r"\bTrac Error\b") + self._tester.go_to_wiki(name) + tc.notfind(r"\bError: Forbidden\b") + self._testenv.enable_authz_permpolicy(""" + [wiki:%(name)s@1] + * = !WIKI_VIEW + [wiki:%(name)s@2] + * = WIKI_VIEW + [wiki:%(name)s@3] + * = !WIKI_VIEW + [wiki:%(name)s] + * = WIKI_VIEW + """ % {'name': name}) + self._tester.go_to_wiki(name, 1) + tc.find(r"\bError: Forbidden\b") + self._tester.go_to_wiki(name, 2) + tc.notfind(r"\bError: Forbidden\b") + self._tester.go_to_wiki(name, 3) + tc.find(r"\bError: Forbidden\b") + self._tester.go_to_wiki(name, 4) + tc.find(r"\bTrac Error\b") + self._tester.go_to_wiki(name) + tc.notfind(r"\bError: Forbidden\b") + self._tester.edit_wiki_page(name) + finally: + self._tester.logout() + self._tester.login('admin') + self._testenv.disable_authz_permpolicy() + + class RegressionTestTicket10274(FunctionalTwillTestCaseSetup): def runTest(self): """Test for regression of http://trac.edgewall.org/ticket/10274""" @@ -139,47 +293,142 @@ class RegressionTestTicket10274(Function class RegressionTestTicket10850(FunctionalTwillTestCaseSetup): - def runTest(self): """Test for regression of http://trac.edgewall.org/ticket/10850""" - pagename = random_unique_camel() - self._tester.create_wiki_page(pagename) + pagename = self._tester.create_wiki_page() # colon characters attachment = self._tester.attach_file_to_wiki( - pagename, tempfilename='2012-09-11_15:36:40-test.tbz2') + pagename, filename='2012-09-11_15:36:40-test.tbz2') base_url = self._tester.url tc.go(base_url + '/attachment/wiki/' + pagename + '/2012-09-11_15:36:40-test.tbz2') tc.notfind('Error: Invalid Attachment') # backslash characters attachment = self._tester.attach_file_to_wiki( - pagename, tempfilename=r'/tmp/back\slash.txt') + pagename, filename=r'/tmp/back\slash.txt') base_url = self._tester.url tc.go(base_url + '/attachment/wiki/' + pagename + r'/back\slash.txt') tc.notfind('Error: Invalid Attachment') # Windows full path attachment = self._tester.attach_file_to_wiki( - pagename, tempfilename=r'z:\tmp\windows:path.txt') + pagename, filename=r'z:\tmp\windows:path.txt') base_url = self._tester.url tc.go(base_url + '/attachment/wiki/' + pagename + r'/windows:path.txt') tc.notfind('Error: Invalid Attachment') # Windows share folder path attachment = self._tester.attach_file_to_wiki( - pagename, tempfilename=r'\\server\share\file:name.txt') + pagename, filename=r'\\server\share\file:name.txt') base_url = self._tester.url tc.go(base_url + '/attachment/wiki/' + pagename + r'/file:name.txt') tc.notfind('Error: Invalid Attachment') +class RegressionTestTicket10957(FunctionalTwillTestCaseSetup): + def runTest(self): + """Test for regression of http://trac.edgewall.org/ticket/10957""" + + self._tester.go_to_front() + try: + self._tester.logout() + + # Check that page can't be created without WIKI_CREATE + page_name = random_unique_camel() + self._tester.go_to_wiki(page_name) + tc.find("Trac Error") + tc.find("Page %s not found" % page_name) + tc.notfind("Create this page") + tc.go(self._tester.url + '/wiki/%s?action=edit' % page_name) + tc.find("Error: Forbidden") + tc.find("WIKI_CREATE privileges are required to perform this " + "operation on %s. You don't have the required permissions." + % page_name) + + # Check that page can be created when user has WIKI_CREATE + self._testenv.grant_perm('anonymous', 'WIKI_CREATE') + content_v1 = random_sentence() + self._tester.create_wiki_page(page_name, content_v1) + tc.find(content_v1) + + # Check that page can't be edited without WIKI_MODIFY + tc.notfind("Edit this page") + tc.notfind("Attach file") + tc.go(self._tester.url + '/wiki/%s?action=edit' % page_name) + tc.find("Error: Forbidden") + tc.find("WIKI_MODIFY privileges are required to perform this " + "operation on %s. You don't have the required permissions." + % page_name) + + # Check that page can be edited when user has WIKI_MODIFY + self._testenv.grant_perm('anonymous', 'WIKI_MODIFY') + self._tester.go_to_wiki(page_name) + tc.find("Edit this page") + tc.find("Attach file") + content_v2 = random_sentence() + self._tester.edit_wiki_page(page_name, content_v2) + tc.find(content_v2) + + # Check that page can be reverted to a previous revision + tc.go(self._tester.url + '/wiki/%s?version=1' % page_name) + tc.find("Revert to this version") + tc.formvalue('modifypage', 'action', 'edit') + tc.submit() + tc.find(content_v1) + + # Check that page can't be reverted without WIKI_MODIFY + self._tester.edit_wiki_page(page_name) + self._testenv.revoke_perm('anonymous', 'WIKI_MODIFY') + tc.go(self._tester.url + '/wiki/%s?version=1' % page_name) + tc.notfind("Revert to this version") + tc.go(self._tester.url + '/wiki/%s?action=edit&version=1' % page_name) + tc.find("WIKI_MODIFY privileges are required to perform this " + "operation on %s. You don't have the required permissions." + % page_name) + + finally: + # Restore pre-test state. + self._tester.login('admin') + self._testenv.revoke_perm('anonymous', 'WIKI_CREATE') + + +class RegressionTestTicket11302(FunctionalTwillTestCaseSetup): + def runTest(self): + """Test for regression of http://trac.edgewall.org/ticket/11302""" + pagename = self._tester.create_wiki_page() + attachment = self._tester.attach_file_to_wiki( + pagename, description="illustrates [./@1#point1]") + self._tester.go_to_wiki(pagename + '?action=edit') + tc.find(r'illustrates <a class="wiki"' + r' href="/wiki/%s\?version=1#point1">@1</a>' % pagename) + + +class RegressionTestTicket11518(FunctionalTwillTestCaseSetup): + def runTest(self): + """Test for regression of http://trac.edgewall.org/ticket/11518 + ResourceNotFound should be raised when version is invalid. + """ + tc.go(self._tester.url + '/wiki/WikiStart?version=1abc') + tc.find(r"<h1>Trac Error</h1>") + tc.find('No version "1abc" for Wiki page "WikiStart') + tc.go(self._tester.url + '/wiki/WikiStart?version=') + tc.find(r"<h1>Trac Error</h1>") + tc.find('No version "" for Wiki page "WikiStart') + + def functionalSuite(suite=None): if not suite: - import trac.tests.functional.testcases - suite = trac.tests.functional.testcases.functionalSuite() + import trac.tests.functional + suite = trac.tests.functional.functionalSuite() suite.addTest(TestWiki()) + suite.addTest(TestWikiAddAttachment()) + suite.addTest(TestWikiPageManipulator()) + suite.addTest(TestWikiHistory()) suite.addTest(TestWikiRename()) suite.addTest(RegressionTestTicket4812()) suite.addTest(RegressionTestTicket10274()) suite.addTest(RegressionTestTicket10850()) + suite.addTest(RegressionTestTicket10957()) + suite.addTest(RegressionTestTicket11302()) + suite.addTest(RegressionTestTicket11518()) if has_docutils: import docutils if get_pkginfo(docutils): @@ -189,6 +438,10 @@ def functionalSuite(suite=None): print "SKIP: reST wiki tests (docutils has no setuptools metadata)" else: print "SKIP: reST wiki tests (no docutils)" + if ConfigObj: + suite.addTest(RegressionTestTicket8976()) + else: + print "SKIP: RegressionTestTicket8976 (ConfigObj not installed)" return suite