Attachment 'RecentChanges.py'

Download

   1 # -*- coding: iso-8859-1 -*-
   2 """
   3     MoinMoin - RecentChanges Macro
   4 
   5     Parameter "ddiffs" by Ralf Zosel <ralf@zosel.com>, 04.12.2003.
   6 
   7     @copyright: 2000-2004 Juergen Hermann <jh@web.de>
   8     @copyright: 2010 Roger D. Haase, added zero-width spaces and soft hyphen word breaks
   9     @license: GNU GPL, see COPYING for details.
  10 """
  11 import time, re
  12 
  13 from MoinMoin import util, wikiutil
  14 from MoinMoin.Page import Page
  15 from MoinMoin.logfile import editlog
  16 from MoinMoin.util.chartypes import chars_lower, chars_upper
  17 
  18 _DAYS_SELECTION = [1, 2, 3, 7, 14, 30, 60, 90]
  19 _MAX_DAYS = 7
  20 _MAX_PAGENAME_LENGTH = 15 # 35
  21 _MAX_COMMENT_LENGTH = 20
  22 
  23 #############################################################################
  24 ### RecentChanges Macro
  25 #############################################################################
  26 
  27 Dependencies = ["time"] # ["user", "pages", "pageparams", "bookmark"]
  28 
  29 def split_page_name(page_name):
  30     """ Return a string with the page name split by zero-width spaces.
  31 
  32     @param page_name: the name of the page to be split
  33     @rtype: unicode
  34     @return: pagename of this page, split into space separated words
  35     """
  36     if len(page_name) <= _MAX_PAGENAME_LENGTH:
  37         return page_name
  38 
  39     zero_width_space = "&#8203;"
  40     # treat "/" as a lower case character
  41     split_regex = re.compile('([%s])([%s])' % ("/" + chars_lower, chars_upper), re.UNICODE)
  42     split_by_spaces = page_name.split(" ")
  43     space_parts = []
  44     for split_by_space in split_by_spaces:
  45         split_by_camelcases = split_regex.sub(r'\1 \2', split_by_space).split(" ")
  46         camelcase_parts = []
  47         for split_by_camelcase in split_by_camelcases:
  48             if len(split_by_camelcase) > _MAX_PAGENAME_LENGTH:
  49                 lowercase_parts = []
  50                 while split_by_camelcase:
  51                     lowercase_parts.append(wikiutil.escape(split_by_camelcase[:_MAX_PAGENAME_LENGTH]))
  52                     split_by_camelcase = split_by_camelcase[_MAX_PAGENAME_LENGTH:]
  53                 camelcase_parts.append(zero_width_space.join(lowercase_parts))
  54             else:
  55                 camelcase_parts.append(wikiutil.escape(split_by_camelcase))
  56         space_parts.append(zero_width_space.join(camelcase_parts))
  57     return " ".join(space_parts)
  58 
  59 def format_comment(request, line):
  60     comment = line.comment
  61     action = line.action
  62     _ = request.getText
  63     if action.startswith('ATT'):
  64         filename = wikiutil.url_unquote(line.extra)
  65         if action == 'ATTNEW':
  66             comment = _("Upload of attachment '%(filename)s'.") % {
  67                 'filename': filename}
  68         elif action == 'ATTDEL':
  69             comment = _("Attachment '%(filename)s' deleted.") % {
  70                 'filename': filename}
  71         elif action == 'ATTDRW':
  72             comment = _("Drawing '%(filename)s' saved.") % {
  73                 'filename': filename}
  74     elif '/REVERT' in action:
  75         rev = int(line.extra)
  76         comment = (_("Revert to revision %(rev)d.") % {'rev': rev}) + " " + comment
  77     elif '/RENAME' in action:
  78         comment = (_("Renamed from '%(oldpagename)s'.") % {'oldpagename': line.extra}) + " " + comment
  79 
  80     return wikiutil.make_breakable(comment, _MAX_COMMENT_LENGTH)
  81 
  82 def format_page_edits(macro, lines, bookmark_usecs):
  83     request = macro.request
  84     _ = request.getText
  85     d = {} # dict for passing stuff to theme
  86     line = lines[0]
  87     pagename = line.pagename
  88     rev = int(line.rev)
  89     tnow = time.time()
  90     is_new = lines[-1].action == 'SAVENEW'
  91     is_renamed = lines[-1].action == 'SAVE/RENAME'
  92     # check whether this page is newer than the user's bookmark
  93     hilite = line.ed_time_usecs > (bookmark_usecs or line.ed_time_usecs)
  94     page = Page(request, pagename)
  95 
  96     html_link = ''
  97     if not page.exists():
  98         img = request.theme.make_icon('deleted')
  99         revbefore = rev - 1
 100         if revbefore and page.exists(rev=revbefore, domain='standard'):
 101             # indicate page was deleted and show diff to last existing revision of it
 102             html_link = page.link_to_raw(request, img, querystr={'action': 'diff'}, rel='nofollow')
 103         else:
 104             # just indicate page was deleted
 105             html_link = img
 106     elif page.isConflict():
 107         img = request.theme.make_icon('conflict')
 108         html_link = page.link_to_raw(request, img, querystr={'action': 'edit'}, rel='nofollow')
 109     elif hilite:
 110         # show special icons if change was after the user's bookmark
 111         if is_new:
 112             img = 'new'
 113         elif is_renamed:
 114             img = 'renamed'
 115         else:
 116             img = 'updated'
 117         img = request.theme.make_icon(img)
 118         html_link = page.link_to_raw(request, img, querystr={'action': 'diff', 'date': '%d' % bookmark_usecs}, rel='nofollow')
 119     else:
 120         # show "DIFF" icon else
 121         img = request.theme.make_icon('diffrc')
 122         html_link = page.link_to_raw(request, img, querystr={'action': 'diff'}, rel='nofollow')
 123 
 124     d['icon_html'] = html_link
 125     d['pagelink_html'] = page.link_to(request, text=split_page_name(page.page_name), no_escape=1)
 126 
 127     # print time of change
 128     d['time_html'] = None
 129     if request.cfg.changed_time_fmt:
 130         tdiff = long(tnow - wikiutil.version2timestamp(long(line.ed_time_usecs))) / 60 # has to be long for py 2.2.x
 131         if tdiff < 100:
 132             d['time_html'] = _("%(mins)dm ago") % {
 133                 'mins': tdiff}
 134         else:
 135             d['time_html'] = time.strftime(request.cfg.changed_time_fmt, line.time_tuple)
 136 
 137     # print editor name or IP
 138     d['editors'] = None
 139     if request.cfg.show_names:
 140         if len(lines) > 1:
 141             counters = {}
 142             for idx in range(len(lines)):
 143                 name = lines[idx].getEditor(request)
 144                 if not name in counters:
 145                     counters[name] = []
 146                 counters[name].append(idx+1)
 147             poslist = [(v, k) for k, v in counters.items()]
 148             poslist.sort()
 149             d['editors'] = []
 150             for positions, name in poslist:
 151                 d['editors'].append("%s&nbsp;[%s]" % (
 152                     name, util.rangelist(positions)))
 153         else:
 154             d['editors'] = [line.getEditor(request)]
 155 
 156     comments = []
 157     for idx in range(len(lines)):
 158         comment = format_comment(request, lines[idx])
 159         if comment:
 160             comments.append((idx+1, comment))
 161 
 162     d['changecount'] = len(lines)
 163     d['comments'] = comments
 164 
 165     img = request.theme.make_icon('info')
 166     d['info_html'] = page.link_to_raw(request, img, querystr={'action': 'info'}, rel='nofollow')
 167 
 168     return request.theme.recentchanges_entry(d)
 169 
 170 def cmp_lines(first, second):
 171     return cmp(first[0], second[0])
 172 
 173 def print_abandoned(macro):
 174     request = macro.request
 175     _ = request.getText
 176     output = []
 177     d = {}
 178     page = macro.formatter.page
 179     pagename = page.page_name
 180     d['page'] = page
 181     d['q_page_name'] = wikiutil.quoteWikinameURL(pagename)
 182     msg = None
 183 
 184     pages = request.rootpage.getPageList()
 185     last_edits = []
 186     for name in pages:
 187         log = Page(request, name).editlog_entry()
 188         if log:
 189             last_edits.append(log)
 190         #   we don't want all Systempages at the beginning of the abandoned list
 191         #    line = editlog.EditLogLine({})
 192         #    line.pagename = page
 193         #    line.ed_time = 0
 194         #    line.comment = 'not edited'
 195         #    line.action = ''
 196         #    line.userid = ''
 197         #    line.hostname = ''
 198         #    line.addr = ''
 199         #    last_edits.append(line)
 200     del pages
 201     last_edits.sort()
 202 
 203     # set max size in days
 204     max_days = min(int(request.values.get('max_days', 0)), _DAYS_SELECTION[-1])
 205     # default to _MAX_DAYS for users without bookmark
 206     if not max_days:
 207         max_days = _MAX_DAYS
 208     d['rc_max_days'] = max_days
 209 
 210     # give known user the option to extend the normal display
 211     if request.user.valid:
 212         d['rc_days'] = _DAYS_SELECTION
 213     else:
 214         d['rc_days'] = None
 215 
 216     d['rc_update_bookmark'] = None
 217     output.append(request.theme.recentchanges_header(d))
 218 
 219     length = len(last_edits)
 220 
 221     index = 0
 222     last_index = 0
 223     day_count = 0
 224 
 225     if length > 0:
 226         line = last_edits[index]
 227         line.time_tuple = request.user.getTime(wikiutil.version2timestamp(line.ed_time_usecs))
 228         this_day = line.time_tuple[0:3]
 229         day = this_day
 230 
 231     while 1:
 232 
 233         index += 1
 234 
 235         if index > length:
 236             break
 237 
 238         if index < length:
 239             line = last_edits[index]
 240             line.time_tuple = request.user.getTime(wikiutil.version2timestamp(line.ed_time_usecs))
 241             day = line.time_tuple[0:3]
 242 
 243         if (day != this_day) or (index == length):
 244             d['bookmark_link_html'] = None
 245             d['date'] = request.user.getFormattedDate(wikiutil.version2timestamp(last_edits[last_index].ed_time_usecs))
 246             output.append(request.theme.recentchanges_daybreak(d))
 247             this_day = day
 248 
 249             for page in last_edits[last_index:index]:
 250                 output.append(format_page_edits(macro, [page], None))
 251             last_index = index
 252             day_count += 1
 253             if (day_count >= max_days):
 254                 break
 255 
 256     d['rc_msg'] = msg
 257     output.append(request.theme.recentchanges_footer(d))
 258     return ''.join(output)
 259 
 260 
 261 def macro_RecentChanges(macro, abandoned=False):
 262     # handle abandoned keyword
 263     if abandoned:
 264         return print_abandoned(macro)
 265 
 266     request = macro.request
 267     _ = request.getText
 268     output = []
 269     user = request.user
 270     page = macro.formatter.page
 271     pagename = page.page_name
 272 
 273     d = {}
 274     d['page'] = page
 275     d['q_page_name'] = wikiutil.quoteWikinameURL(pagename)
 276 
 277     log = editlog.EditLog(request)
 278 
 279     tnow = time.time()
 280     msg = ""
 281 
 282     # get bookmark from valid user
 283     bookmark_usecs = request.user.getBookmark() or 0
 284 
 285     # add bookmark link if valid user
 286     d['rc_curr_bookmark'] = None
 287     d['rc_update_bookmark'] = None
 288     if request.user.valid:
 289         d['rc_curr_bookmark'] = _('(no bookmark set)')
 290         if bookmark_usecs:
 291             currentBookmark = wikiutil.version2timestamp(bookmark_usecs)
 292             currentBookmark = user.getFormattedDateTime(currentBookmark)
 293             currentBookmark = _('(currently set to %s)') % currentBookmark
 294             deleteBookmark = page.link_to(request, _("Delete bookmark"), querystr={'action': 'bookmark', 'time': 'del'}, rel='nofollow')
 295             d['rc_curr_bookmark'] = currentBookmark + ' ' + deleteBookmark
 296 
 297         version = wikiutil.timestamp2version(tnow)
 298         d['rc_update_bookmark'] = page.link_to(request, _("Set bookmark"), querystr={'action': 'bookmark', 'time': '%d' % version}, rel='nofollow')
 299 
 300     # set max size in days
 301     max_days = min(int(request.values.get('max_days', 0)), _DAYS_SELECTION[-1])
 302     # default to _MAX_DAYS for useres without bookmark
 303     if not max_days and not bookmark_usecs:
 304         max_days = _MAX_DAYS
 305     d['rc_max_days'] = max_days
 306 
 307     # give known user the option to extend the normal display
 308     if request.user.valid:
 309         d['rc_days'] = _DAYS_SELECTION
 310     else:
 311         d['rc_days'] = []
 312 
 313     output.append(request.theme.recentchanges_header(d))
 314 
 315     pages = {}
 316     ignore_pages = {}
 317 
 318     today = request.user.getTime(tnow)[0:3]
 319     this_day = today
 320     day_count = 0
 321 
 322     for line in log.reverse():
 323 
 324         if not request.user.may.read(line.pagename):
 325             continue
 326 
 327         line.time_tuple = request.user.getTime(wikiutil.version2timestamp(line.ed_time_usecs))
 328         day = line.time_tuple[0:3]
 329         hilite = line.ed_time_usecs > (bookmark_usecs or line.ed_time_usecs)
 330 
 331         if ((this_day != day or (not hilite and not max_days))) and len(pages) > 0:
 332             # new day or bookmark reached: print out stuff
 333             this_day = day
 334             for p in pages:
 335                 ignore_pages[p] = None
 336             pages = pages.values()
 337             pages.sort(cmp_lines)
 338             pages.reverse()
 339 
 340             if request.user.valid:
 341                 bmtime = pages[0][0].ed_time_usecs
 342                 d['bookmark_link_html'] = page.link_to(request, _("Set bookmark"), querystr={'action': 'bookmark', 'time': '%d' % bmtime}, rel='nofollow')
 343             else:
 344                 d['bookmark_link_html'] = None
 345             d['date'] = request.user.getFormattedDate(wikiutil.version2timestamp(pages[0][0].ed_time_usecs))
 346             output.append(request.theme.recentchanges_daybreak(d))
 347 
 348             for p in pages:
 349                 output.append(format_page_edits(macro, p, bookmark_usecs))
 350             pages = {}
 351             day_count += 1
 352             if max_days and (day_count >= max_days):
 353                 break
 354 
 355         elif this_day != day:
 356             # new day but no changes
 357             this_day = day
 358 
 359         if line.pagename in ignore_pages:
 360             continue
 361 
 362         # end listing by default if user has a bookmark and we reached it
 363         if not max_days and not hilite:
 364             msg = _('[Bookmark reached]')
 365             break
 366 
 367         if line.pagename in pages:
 368             pages[line.pagename].append(line)
 369         else:
 370             pages[line.pagename] = [line]
 371     else:
 372         if len(pages) > 0:
 373             # end of loop reached: print out stuff
 374             # XXX duplicated code from above
 375             # but above does not trigger if we have the first day in wiki history
 376             for p in pages:
 377                 ignore_pages[p] = None
 378             pages = pages.values()
 379             pages.sort(cmp_lines)
 380             pages.reverse()
 381 
 382             if request.user.valid:
 383                 bmtime = pages[0][0].ed_time_usecs
 384                 d['bookmark_link_html'] = page.link_to(request, _("Set bookmark"), querystr={'action': 'bookmark', 'time': '%d' % bmtime}, rel='nofollow')
 385             else:
 386                 d['bookmark_link_html'] = None
 387             d['date'] = request.user.getFormattedDate(wikiutil.version2timestamp(pages[0][0].ed_time_usecs))
 388             output.append(request.theme.recentchanges_daybreak(d))
 389 
 390             for p in pages:
 391                 output.append(format_page_edits(macro, p, bookmark_usecs))
 392 
 393 
 394     d['rc_msg'] = msg
 395     output.append(request.theme.recentchanges_footer(d))
 396 
 397     return ''.join(output)

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2010-08-19 16:16:12, 73.3 KB) [[attachment:Page.py]]
  • [get | view] (2010-08-19 19:29:46, 13.9 KB) [[attachment:RecentChanges.py]]
  • [get | view] (2010-08-22 20:41:59, 10.7 KB) [[attachment:recentchanges.diff]]
  • [get | view] (2010-08-19 16:16:54, 91.8 KB) [[attachment:wikiutil.py]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.