Attachment 'StatusAttachments.py'
Download 1 # -*- coding: utf-8 -*-
2 """
3 MoinMoin - Macro for Attachment Administration
4
5 Discover unused (not linked) and missing (not yet uploaded) attachments
6
7 @copyright: 2015-2018, David Linke, MoinMoin:DavidLinke, https://github.com/dalito
8 @license: GNU GPL, see COPYING for details.
9 """
10 import os
11 import sys
12
13 from MoinMoin import config
14 from MoinMoin import wikiutil
15 from MoinMoin.PageEditor import PageEditor
16 from MoinMoin.parser.text_moin_wiki import Parser
17 from MoinMoin.action import AttachFile
18
19 # Should only the superuser be allowed to use this macro ?
20 SUPERUSER_ONLY = False
21
22
23 def macro_StatusAttachments(macro):
24 """
25 Purpose: Discover unused (not linked) attachments and missing attachment
26
27 This macro finds and reports
28 (i) attachments that are stored on pages put linked from nowhere
29 (ii) attachment-links for which the attachment is not yet uploaded.
30
31 The underlay directory is excluded.
32 """
33 _ = macro.request.getText
34 request = macro.request
35
36 # do not show to users not in superuser list
37 if SUPERUSER_ONLY and not request.user.isSuperUser():
38 error = _(u'Only superusers can use StatusAttachments macro.')
39 # Send page with an error message
40 request.theme.add_msg(error, 'info')
41 return ''
42
43 # do import from plugin "extensions" dir
44 LinkParser = wikiutil.importWikiPlugin(
45 request.cfg, 'parser', 'text_moin_wiki_links', 'LinkParser'
46 )
47
48 # create instance of parser for link extraction
49 lparser = LinkParser()
50
51 # collect info per page in lists
52 stored_attachments = {}
53 attachments_no_ext = {}
54 links_to_existing_atts = {}
55 links_to_missing_atts = {}
56 stored_non_linked_atts = {}
57
58 # get list of all pagenames excluding underlay
59 pages = request.rootpage.getPageDict(user=request.user,
60 include_underlay=False)
61
62 for pagename in pages:
63 page = PageEditor(request, pagename)
64
65 # (i) get linked attachments by parsing raw text
66 raw = page.get_raw_body()
67 atts = lparser.find_links(raw, link_filter=lparser.is_attachment)
68 for att in atts:
69 link = att.split(':', 1)[1]
70 if '/' in link:
71 storage_page, filename = link.rsplit('/', 1)
72 else:
73 storage_page, filename = pagename, link
74 filename = wikiutil.taintfilename(filename)
75 if AttachFile.exists(request, storage_page, filename):
76 if storage_page in links_to_existing_atts:
77 links_to_existing_atts[storage_page].append(filename)
78 else:
79 links_to_existing_atts[storage_page] = [filename]
80 else:
81 if storage_page in links_to_missing_atts:
82 if filename not in links_to_missing_atts[storage_page]:
83 links_to_missing_atts[storage_page].append(filename)
84 else:
85 links_to_missing_atts[storage_page] = [filename]
86
87 # (ii) get stored attachments by looking at file system
88 # & (iii) get stored attachments without any extension
89 page_att_dir = AttachFile.getAttachDir(request, pagename)
90 if os.path.isdir(page_att_dir):
91 atts, atts_no_ext = [], []
92 for fname in os.listdir(page_att_dir):
93 atts.append(fname.decode(config.charset))
94 if not os.path.splitext(fname)[1]:
95 atts_no_ext.append(fname.decode(config.charset))
96 if atts:
97 stored_attachments[pagename] = atts
98 if atts_no_ext:
99 attachments_no_ext[pagename] = atts_no_ext
100
101 # when checking for availability of attachments we need to consider that
102 # filenames are case insensitive on some platforms
103 if sys.platform == 'win32':
104 links_to_existing_atts_fs = {}
105 for p in links_to_existing_atts:
106 links_to_existing_atts_fs[p] = [os.path.normcase(att) for att in
107 links_to_existing_atts[p]]
108 else:
109 links_to_existing_atts_fs = links_to_existing_atts
110
111 # Find stored attachments that are not linked from anywhere
112 for pagename in stored_attachments:
113 for att in stored_attachments[pagename]:
114 # look up in links_to_existing_atts if linked
115 if (os.path.normcase(att)
116 in links_to_existing_atts_fs.get(pagename, [])):
117 continue
118
119 # keep name of non-linked attachment
120 if pagename in stored_non_linked_atts:
121 stored_non_linked_atts[pagename].append(att)
122 else:
123 stored_non_linked_atts[pagename] = [att]
124
125 # Created formatted output. We create wiki raw code that is then rendered.
126 # Compare to using formatters this is much less verbose (but slower).
127
128 # (i) attachments that are stored on pages put linked from nowhere
129 ret = []
130 ret.append('<<TableOfContents>>')
131 ret.append(u'== %s ==' %
132 _(u'Attachments that are not linked from anywhere'))
133
134 if not stored_non_linked_atts:
135 ret.append(u" * None!")
136 else:
137 ret.append(u" * Found '''%i''' attachments that are not linked." %
138 len(reduce(list.__add__, stored_non_linked_atts.values())))
139 for pagename in sorted(stored_non_linked_atts):
140 ret.append(u" * '''[[%s||&action=AttachFile]]'''" % pagename)
141 for att in sorted(stored_non_linked_atts[pagename]):
142 ret.append(u" * `%s`" % att)
143
144 # (ii) attachment-links for which the attachment is not yet uploaded.
145 ret.append(u'== %s ==' %
146 _(u'Attachments that are linked but missing'))
147 if not links_to_missing_atts:
148 ret.append(u" * None!")
149 else:
150 ret.append(u" * Found '''%i''' links to missing attachments." %
151 len(reduce(list.__add__, links_to_missing_atts.values())))
152 for pagename in sorted(links_to_missing_atts):
153 ret.append(u" * '''[[%s]]'''" % pagename)
154 for att in sorted(links_to_missing_atts[pagename]):
155 ret.append(u" * `%s`" % att)
156
157 # (iii) List all stored attachments without any extension
158 ret.append(u'== %s ==' %
159 _(u'Attachments lacking a file extension'))
160 if not attachments_no_ext:
161 ret.append(u" * None!")
162 else:
163 ret.append(u" * Found '''%i''' attachments without extension." %
164 len(reduce(list.__add__, attachments_no_ext.values())))
165 for pagename in sorted(attachments_no_ext):
166 ret.append(u" * '''[[%s||&action=AttachFile]]'''" % pagename)
167 for att in sorted(attachments_no_ext[pagename]):
168 ret.append(u" * `%s`" % att)
169
170 return wikiutil.renderText(request, Parser, '\n'.join(ret))
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.You are not allowed to attach a file to this page.