OLD | NEW |
1 # Copyright: 2012 MoinMoin:CheerXiao | 1 # Copyright: 2012 MoinMoin:CheerXiao |
2 # License: GNU GPL v2 (or any later version), see LICENSE.txt for details. | 2 # License: GNU GPL v2 (or any later version), see LICENSE.txt for details. |
3 | 3 |
4 """ | 4 """ |
5 MoinMoin - Ticket itemtype | 5 MoinMoin - Ticket itemtype |
6 """ | 6 """ |
7 | 7 |
8 | 8 |
9 from __future__ import absolute_import, division | 9 from __future__ import absolute_import, division |
10 | 10 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
71 required_by = BackReference.using(label=L_("Required By")) | 71 required_by = BackReference.using(label=L_("Required By")) |
72 subscribers = BackReference.using(label=L_("Subscribers")) | 72 subscribers = BackReference.using(label=L_("Subscribers")) |
73 | 73 |
74 def _load(self, item): | 74 def _load(self, item): |
75 id_ = item.meta[ITEMID] | 75 id_ = item.meta[ITEMID] |
76 self['supersedes'].set(Term(SUPERSEDED_BY, id_)) | 76 self['supersedes'].set(Term(SUPERSEDED_BY, id_)) |
77 self['required_by'].set(Term(DEPENDS_ON, id_)) | 77 self['required_by'].set(Term(DEPENDS_ON, id_)) |
78 self['subscribers'].set(Term(SUBSCRIBED_ITEMS, id_)) | 78 self['subscribers'].set(Term(SUBSCRIBED_ITEMS, id_)) |
79 | 79 |
80 | 80 |
81 class TicketForm(BaseModifyForm): | 81 class TicketBaseForm(BaseModifyForm): |
82 meta = TicketMetaForm | |
83 backrefs = TicketBackRefForm | 82 backrefs = TicketBackRefForm |
84 message = OptionalMultilineText.using(label=L_("Message")).with_properties(r
ows=8, cols=80) | 83 message = OptionalMultilineText.using(label=L_("Message")).with_properties(r
ows=8, cols=80) |
85 | 84 |
86 def _load(self, item): | 85 def _load(self, item): |
87 meta = item.prepare_meta_for_modify(item.meta) | |
88 self['meta'].set(meta, 'duck') | |
89 # XXX need a more explicit way to test for item creation/modification | 86 # XXX need a more explicit way to test for item creation/modification |
90 if ITEMID in item.meta: | 87 if ITEMID in item.meta: |
91 self['backrefs']._load(item) | 88 self['backrefs']._load(item) |
92 | 89 |
93 | 90 |
94 class TicketSubmitForm(TicketForm): | 91 class TicketModifyForm(TicketBaseForm): |
| 92 meta = TicketMetaForm |
| 93 |
| 94 def _load(self, item): |
| 95 super(TicketModifyForm, self)._load(item) |
| 96 meta = item.prepare_meta_for_modify(item.meta) |
| 97 self['meta'].set(meta, 'duck') |
| 98 |
| 99 |
| 100 class TicketSubmitForm(TicketModifyForm): |
95 submit_label = L_("Submit ticket") | 101 submit_label = L_("Submit ticket") |
96 | 102 |
97 def _dump(self, item): | 103 def _dump(self, item): |
98 # initial metadata for Ticket-itemtyped item | 104 # initial metadata for Ticket-itemtyped item |
99 meta = { | 105 meta = { |
100 ITEMTYPE: item.itemtype, | 106 ITEMTYPE: item.itemtype, |
101 # XXX support other markups | 107 # XXX support other markups |
102 CONTENTTYPE: 'text/x.moin.wiki;charset=utf-8', | 108 CONTENTTYPE: 'text/x.moin.wiki;charset=utf-8', |
103 'closed': False, | 109 'closed': False, |
104 } | 110 } |
105 meta.update(self['meta'].value) | 111 meta.update(self['meta'].value) |
106 return meta, message_markup(self['message'].value) | 112 return meta, message_markup(self['message'].value) |
107 | 113 |
108 | 114 |
109 class TicketUpdateForm(TicketForm): | 115 class TicketUpdateForm(TicketModifyForm): |
110 submit = SelectSubmit.valued('update', 'update_negate_status') | 116 submit = SelectSubmit.valued('update', 'update_negate_status') |
111 | 117 |
112 def _load(self, item): | 118 def _load(self, item): |
113 super(TicketUpdateForm, self)._load(item) | 119 super(TicketUpdateForm, self)._load(item) |
114 self['submit'].properties['labels'] = { | 120 self['submit'].properties['labels'] = { |
115 'update': L_('Update ticket'), | 121 'update': L_('Update ticket'), |
116 'update_negate_status': (L_('Update & reopen ticket') if item.meta.g
et('closed') | 122 'update_negate_status': (L_('Update & reopen ticket') if item.meta.g
et('closed') |
117 else L_('Update & close ticket')) | 123 else L_('Update & close ticket')) |
118 } | 124 } |
119 | 125 |
120 def _dump(self, item): | 126 def _dump(self, item): |
121 # Since the metadata form for tickets is an incomplete one, we load the | 127 # Since the metadata form for tickets is an incomplete one, we load the |
122 # original meta and update it with those from the metadata editor | 128 # original meta and update it with those from the metadata editor |
123 meta = item.meta_filter(item.prepare_meta_for_modify(item.meta)) | 129 meta = item.meta_filter(item.prepare_meta_for_modify(item.meta)) |
124 meta.update(self['meta'].value) | 130 meta.update(self['meta'].value) |
125 if self['submit'].value == 'update_negate_status': | 131 if self['submit'].value == 'update_negate_status': |
126 meta['closed'] = not meta.get('closed') | 132 meta['closed'] = not meta.get('closed') |
127 | 133 |
128 data = item.content.data_storage_to_internal(item.content.data) | 134 data = item.content.data_storage_to_internal(item.content.data) |
129 message = self['message'].value | 135 message = self['message'].value |
130 if message: | 136 if message: |
131 data += message_markup(message) | 137 data += message_markup(message) |
132 | 138 |
133 return meta, data | 139 return meta, data |
134 | 140 |
135 | 141 |
| 142 class TicketShowForm(TicketBaseForm): |
| 143 """ |
| 144 Form used for the +show view of a ticket. |
| 145 |
| 146 No TicketMetaForm here, since the +show view doesn't allow modifying metadat
a. |
| 147 """ |
| 148 |
| 149 |
136 # XXX Ideally we should generate DOM instead of moin wiki source. But | 150 # XXX Ideally we should generate DOM instead of moin wiki source. But |
137 # currently this is not very useful, since | 151 # currently this is not very useful, since |
138 # * DOM cannot be stored directly, it has to be converted to some markup first | 152 # * DOM cannot be stored directly, it has to be converted to some markup first |
139 # * DOM -> markup conversion is only available for moinwiki | 153 # * DOM -> markup conversion is only available for moinwiki |
140 | 154 |
141 # XXX How to do i18n on this? | 155 # XXX How to do i18n on this? |
142 | 156 |
143 def message_markup(message): | 157 def message_markup(message): |
144 return u'''{{{{{{#!wiki tip | 158 return u'''{{{{{{#!wiki tip |
145 %(author)s wrote on <<DateTime(%(timestamp)d)>>: | 159 %(author)s wrote on <<DateTime(%(timestamp)d)>>: |
146 | 160 |
147 %(message)s | 161 %(message)s |
148 }}}}}} | 162 }}}}}} |
149 ''' % dict(author=flaskg.user.name[0], timestamp=time.time(), message=message) | 163 ''' % dict(author=flaskg.user.name[0], timestamp=time.time(), message=message) |
150 | 164 |
151 | 165 |
152 @register | 166 @register |
153 class Ticket(Contentful): | 167 class Ticket(Contentful): |
154 itemtype = ITEMTYPE_TICKET | 168 itemtype = ITEMTYPE_TICKET |
155 display_name = L_('Ticket') | 169 display_name = L_('Ticket') |
156 description = L_('Ticket item') | 170 description = L_('Ticket item') |
| 171 show_template = 'ticket/show.html' |
157 submit_template = 'ticket/submit.html' | 172 submit_template = 'ticket/submit.html' |
158 modify_template = 'ticket/modify.html' | 173 modify_template = 'ticket/modify.html' |
159 | 174 |
160 def do_show(self, revid): | 175 def _do_show_or_modify(self, show): |
161 if revid != CURRENT: | |
162 # TODO When requesting a historical version, show a readonly view | |
163 abort(403) | |
164 else: | |
165 return self.do_modify() | |
166 | |
167 def do_modify(self): | |
168 is_new = isinstance(self.content, NonExistentContent) | 176 is_new = isinstance(self.content, NonExistentContent) |
169 closed = self.meta.get('closed') | 177 closed = self.meta.get('closed') |
170 | 178 |
171 Form = TicketSubmitForm if is_new else TicketUpdateForm | 179 if show: |
| 180 Form = TicketShowForm |
| 181 template = self.show_template |
| 182 else: |
| 183 Form = TicketSubmitForm if is_new else TicketUpdateForm |
| 184 template = self.submit_template if is_new else self.modify_template |
172 | 185 |
173 if request.method in ['GET', 'HEAD']: | 186 if request.method in ['GET', 'HEAD']: |
174 form = Form.from_item(self) | 187 form = Form.from_item(self) |
175 elif request.method == 'POST': | 188 elif request.method == 'POST': |
176 form = Form.from_request(request) | 189 form = Form.from_request(request) |
177 if form.validate(): | 190 if form.validate(): |
178 meta, data = form._dump(self) | 191 meta, data = form._dump(self) |
179 try: | 192 try: |
180 self.modify(meta, data) | 193 self.modify(meta, data) |
181 except AccessDenied: | 194 except AccessDenied: |
182 abort(403) | 195 abort(403) |
183 else: | 196 else: |
184 return redirect(url_for('.show_item', item_name=self.name)) | 197 return redirect(url_for('.show_item', item_name=self.name)) |
185 | 198 |
186 # XXX When creating new item, suppress the "foo doesn't exist. Create it
?" dummy content | 199 # XXX When creating new item, suppress the "foo doesn't exist. Create it
?" dummy content |
187 data_rendered = None if is_new else Markup(self.content._render_data()) | 200 data_rendered = None if is_new else Markup(self.content._render_data()) |
188 | 201 |
189 return render_template(self.submit_template if is_new else self.modify_t
emplate, | 202 return render_template(template, |
190 is_new=is_new, | 203 is_new=is_new, |
191 closed=closed, | 204 closed=closed, |
192 item_name=self.name, | 205 item_name=self.name, |
193 data_rendered=data_rendered, | 206 data_rendered=data_rendered, |
194 form=form, | 207 form=form, |
| 208 item=self, |
| 209 display_fields=display_fields, |
195 ) | 210 ) |
196 | 211 |
| 212 def do_show(self, revid): |
| 213 if revid != CURRENT: |
| 214 # TODO When requesting a historical version, show a readonly view |
| 215 abort(403) |
| 216 else: |
| 217 return self._do_show_or_modify(show=True) |
| 218 |
| 219 def do_modify(self): |
| 220 return self._do_show_or_modify(show=False) |
| 221 |
197 | 222 |
198 ITEMTYPE_TICKET_INDEX = u'ticketindex' | 223 ITEMTYPE_TICKET_INDEX = u'ticketindex' |
199 | 224 |
200 | 225 |
201 @register | 226 @register |
202 class TicketIndex(Default): | 227 class TicketIndex(Default): |
203 itemtype = ITEMTYPE_TICKET_INDEX | 228 itemtype = ITEMTYPE_TICKET_INDEX |
204 display_name = L_('Ticket Index') | 229 display_name = L_('Ticket Index') |
205 description = L_('An index for all tickets under it') | 230 description = L_('An index for all tickets under it') |
206 show_template = 'ticket/index.html' | 231 show_template = 'ticket/index.html' |
207 | 232 |
208 def do_show(self, revid): | 233 def do_show(self, revid): |
209 prefix = self.subitems_prefix | 234 prefix = self.subitems_prefix |
210 prefixlen = len(prefix) | 235 prefixlen = len(prefix) |
211 query = (Term(WIKINAME, app.cfg.interwikiname) & | 236 query = (Term(WIKINAME, app.cfg.interwikiname) & |
212 Term(ITEMTYPE, ITEMTYPE_TICKET) & | 237 Term(ITEMTYPE, ITEMTYPE_TICKET) & |
213 Prefix(NAME_EXACT, prefix)) | 238 Prefix(NAME_EXACT, prefix)) |
214 revs = flaskg.storage.search(query, limit=None) | 239 revs = flaskg.storage.search(query, limit=None) |
215 tickets = [] | 240 tickets = [] |
216 for rev in revs: | 241 for rev in revs: |
217 fullname = rev.meta[NAME][0] | 242 fullname = rev.meta[NAME][0] |
218 relname = fullname[prefixlen:] | 243 relname = fullname[prefixlen:] |
219 tickets.append(IndexEntry(relname, fullname, rev.meta)) | 244 tickets.append(IndexEntry(relname, fullname, rev.meta)) |
220 return render_template(self.show_template, | 245 return render_template(self.show_template, |
221 item_name=self.name, | 246 item_name=self.name, |
222 data_rendered=Markup(self.content._render_data())
, | 247 data_rendered=Markup(self.content._render_data())
, |
223 fields=display_fields, | 248 fields=display_fields, |
224 tickets=tickets | 249 tickets=tickets |
225 ) | 250 ) |
OLD | NEW |