Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

#2429: uses modified time of wiki page for tags_change.time column wi…

…th `threading.local`
  • Loading branch information...
commit afbcd4dcc824a1efd71cb845dbc0b45aaca1ca5f 1 parent c5a79c9
@jun66j5 authored
View
36 tractags/api.py
@@ -8,6 +8,11 @@
#
import re
+try:
+ import threading
+except ImportError:
+ import dummy_threading as threading
+ threading._get_ident = lambda: 0
from operator import itemgetter
from pkg_resources import resource_filename
@@ -220,7 +225,7 @@ def get_all_tags(req, filter=None):
def get_resource_tags(req, resource, when=None):
"""Get tags for a Resource object."""
- def set_resource_tags(req, resource, tags, comment=u''):
+ def set_resource_tags(req, resource, tags, comment=u'', when=None):
"""Set tags for a resource."""
def reparent_resource_tags(req, resource, old_id, comment=u''):
@@ -290,12 +295,12 @@ def get_resource_tags(self, req, resource, when=None):
return
return resource_tags(self.env, resource, when=when)
- def set_resource_tags(self, req, resource, tags, comment=u''):
+ def set_resource_tags(self, req, resource, tags, comment=u'', when=None):
assert resource.realm == self.realm
if not self.check_permission(req.perm(resource), 'modify'):
raise PermissionError(resource=resource, env=self.env)
tag_resource(self.env, resource, author=req.authname, tags=tags,
- log=self.revisable)
+ log=self.revisable, when=when)
def reparent_resource_tags(self, req, resource, old_id, comment=u''):
assert resource.realm == self.realm
@@ -398,14 +403,14 @@ def get_tags(self, req, resource, when=None):
return set(self._get_provider(resource.realm) \
.get_resource_tags(req, resource, when=when))
- def set_tags(self, req, resource, tags, comment=u''):
+ def set_tags(self, req, resource, tags, comment=u'', when=None):
"""Set tags on a resource.
Existing tags are replaced.
"""
try:
return self._get_provider(resource.realm) \
- .set_resource_tags(req, resource, set(tags), comment)
+ .set_resource_tags(req, resource, set(tags), comment, when)
except TypeError:
# Handle old style tag providers gracefully.
return self._get_provider(resource.realm) \
@@ -534,3 +539,24 @@ def _get_provider(self, realm):
except KeyError:
raise InvalidTagRealm(_("Tags are not supported on the '%s' realm")
% realm)
+
+
+class RequestsProxy(object):
+
+ def __init__(self):
+ self.current = threading.local()
+
+ def get(self):
+ try:
+ return self.current.req
+ except:
+ return None
+
+ def set(self, req):
+ self.current.req = req
+
+ def reset(self):
+ self.current.req = None
+
+
+requests = RequestsProxy()
View
9 tractags/model.py
@@ -77,7 +77,7 @@ def tag_frequency(env, realm, filter=None, db=None):
yield (row[0], row[1])
def tag_resource(env, resource, old_id=None, author='anonymous', tags=[],
- log=False):
+ log=False, when=None):
"""Save tags and tag changes for a Trac resource.
This function combines delete, reparent and set actions now, but it could
@@ -85,6 +85,10 @@ def tag_resource(env, resource, old_id=None, author='anonymous', tags=[],
"""
db = _get_db(env)
cursor = db.cursor()
+ if when is None:
+ when = datetime.now(utc)
+ if isinstance(when, datetime):
+ when = to_utimestamp(when)
if old_id:
cursor.execute("""
@@ -123,8 +127,7 @@ def tag_resource(env, resource, old_id=None, author='anonymous', tags=[],
INSERT INTO tags_change
(tagspace, name, time, author, oldtags, newtags)
VALUES (%s,%s,%s,%s,%s,%s)
- """, (resource.realm, to_unicode(resource.id),
- to_utimestamp(datetime.now(utc)), author,
+ """, (resource.realm, to_unicode(resource.id), when, author,
u' '.join(sorted(map(to_unicode, old_tags))),
u' '.join(sorted(map(to_unicode, tags))),))
db.commit()
View
8 tractags/ticket.py
@@ -111,7 +111,8 @@ def get_resource_tags(self, req, resource):
return
return self._ticket_tags(ticket)
- def set_resource_tags(self, req, ticket_or_resource, tags, comment=u''):
+ def set_resource_tags(self, req, ticket_or_resource, tags, comment=u'',
+ when=None):
try:
resource = ticket_or_resource.resource
except AttributeError:
@@ -176,7 +177,8 @@ def ticket_created(self, ticket):
"""Called when a ticket is created."""
# Add any tags unconditionally.
self.set_resource_tags(Mock(authname=ticket['reporter'],
- perm=MockPerm()), ticket, None)
+ perm=MockPerm()),
+ ticket, None, ticket['time'])
if self.use_cache:
# Invalidate resource cache.
del self._tagged_resources
@@ -186,7 +188,7 @@ def ticket_changed(self, ticket, comment, author, old_values):
# Sync only on change of ticket fields, that are exposed as tags.
if any(f in self.fields for f in old_values.keys()):
self.set_resource_tags(Mock(authname=author, perm=MockPerm()),
- ticket, None)
+ ticket, None, ticket['changetime'])
if self.use_cache:
# Invalidate resource cache.
del self._tagged_resources
View
26 tractags/wiki.py
@@ -25,7 +25,7 @@
from trac.wiki.model import WikiPage
from trac.wiki.web_ui import WikiModule
-from tractags.api import DefaultTagProvider, TagSystem, _, tagn_
+from tractags.api import DefaultTagProvider, TagSystem, _, requests, tagn_
from tractags.compat import to_utimestamp
from tractags.macros import TagTemplateProvider
from tractags.model import delete_tags, tag_changes
@@ -94,6 +94,9 @@ def post_process_request(self, req, template, data, content_type):
if req.args.get('action') == 'history' and \
data and 'history' in data:
self._post_process_request_history(req, data)
+ if req.method == 'POST' and req.path_info.startswith('/wiki/') and \
+ 'save' in req.args:
+ requests.reset()
return (template, data, content_type)
# ITemplateStreamFilter methods
@@ -120,9 +123,9 @@ def validate_wiki_page(self, req, page):
and req.path_info.startswith('/wiki') and 'save' in req.args:
page_modified = req.args.get('text') != page.old_text or \
page.readonly != int('readonly' in req.args)
- # Always save tags if the page has been otherwise modified.
if page_modified:
- self._update_tags(req, page)
+ requests.set(req)
+ req.add_redirect_listener(self._redirect_listener)
elif page.version > 0:
# If the page hasn't been otherwise modified, save tags and
# redirect to avoid the "page has not been modified" warning.
@@ -133,10 +136,14 @@ def validate_wiki_page(self, req, page):
# IWikiChangeListener methods
def wiki_page_added(self, page):
- pass
+ req = requests.get()
+ if req:
+ self._update_tags(req, page, page.time)
def wiki_page_changed(self, page, version, t, comment, author, ipnr):
- pass
+ req = requests.get()
+ if req:
+ self._update_tags(req, page, page.time)
def wiki_page_renamed(self, page, old_name):
"""Called when a page has been renamed (since Trac 0.12)."""
@@ -169,6 +176,9 @@ def _page_tags(self, req):
tags = sorted(tag_system.get_tags(req, resource, when=tags_version))
return tags
+ def _redirect_listener(self, req, url, permanent):
+ requests.reset()
+
def _post_process_request_edit(self, req):
# Retrieve template resource to be queried for tags.
template_pagename = ''.join([WikiModule.PAGE_TEMPLATES_PREFIX,
@@ -195,7 +205,7 @@ def _post_process_request_history(self, req, data):
for page_history in page_histories:
while tags_histories and \
- tags_histories[0][0] > page_history['date']:
+ tags_histories[0][0] >= page_history['date']:
tags_history = tags_histories.pop(0)
date = tags_history[0]
author = tags_history[1]
@@ -242,13 +252,13 @@ def _wiki_view(self, req, stream):
return stream | (Transformer('//div[contains(@class,"wikipage")]')
.after(insert))
- def _update_tags(self, req, page):
+ def _update_tags(self, req, page, when=None):
tag_system = TagSystem(self.env)
newtags = split_into_tags(req.args.get('tags', ''))
oldtags = tag_system.get_tags(req, page.resource)
if oldtags != newtags:
- tag_system.set_tags(req, page.resource, newtags)
+ tag_system.set_tags(req, page.resource, newtags, when=when)
return True
return False

1 comment on commit afbcd4d

@hasienda

I've finally take the time to check these changes. Works flawlessly. Please push this as soon as you can, it makes the new feature complete after all, and I'd like to push the TagsPlugin release again over the coming holidays. Thanks for your dedication to fix this non-trivial syncing issue. The request proxy approach might come in handy for similar issues as well.

Please sign in to comment.
Something went wrong with that request. Please try again.