|
a/Allura/allura/controllers/discuss.py |
|
b/Allura/allura/controllers/discuss.py |
|
... |
|
... |
36 |
from allura.lib.security import require, has_access, require_access
|
36 |
from allura.lib.security import require, has_access, require_access
|
37 |
from allura.lib.helpers import DateTimeConverter
|
37 |
from allura.lib.helpers import DateTimeConverter
|
38 |
|
38 |
|
39 |
from allura.lib.widgets import discuss as DW
|
39 |
from allura.lib.widgets import discuss as DW
|
40 |
from .attachments import AttachmentsController, AttachmentController
|
40 |
from .attachments import AttachmentsController, AttachmentController
|
|
|
41 |
from .feed import Feed, FeedController
|
41 |
|
42 |
|
42 |
log = logging.getLogger(__name__)
|
43 |
log = logging.getLogger(__name__)
|
43 |
|
44 |
|
44 |
class pass_validator(object):
|
45 |
class pass_validator(object):
|
45 |
def validate(self, v, s):
|
46 |
def validate(self, v, s):
|
|
... |
|
... |
66 |
thread = DW.Thread()
|
67 |
thread = DW.Thread()
|
67 |
post = DW.Post()
|
68 |
post = DW.Post()
|
68 |
thread_header = DW.ThreadHeader()
|
69 |
thread_header = DW.ThreadHeader()
|
69 |
|
70 |
|
70 |
# Controllers
|
71 |
# Controllers
|
71 |
class DiscussionController(BaseController):
|
72 |
class DiscussionController(BaseController, FeedController):
|
72 |
M=ModelConfig
|
73 |
M=ModelConfig
|
73 |
W=WidgetConfig
|
74 |
W=WidgetConfig
|
74 |
|
75 |
|
75 |
def __init__(self):
|
76 |
def __init__(self):
|
76 |
setattr(self, 'feed.rss', self.feed)
|
|
|
77 |
setattr(self, 'feed.atom', self.feed)
|
|
|
78 |
if not hasattr(self, 'ThreadController'):
|
77 |
if not hasattr(self, 'ThreadController'):
|
79 |
self.ThreadController = ThreadController
|
78 |
self.ThreadController = ThreadController
|
80 |
if not hasattr(self, 'PostController'):
|
79 |
if not hasattr(self, 'PostController'):
|
81 |
self.PostController = PostController
|
80 |
self.PostController = PostController
|
82 |
if not hasattr(self, 'AttachmentController'):
|
81 |
if not hasattr(self, 'AttachmentController'):
|
|
... |
|
... |
104 |
else:
|
103 |
else:
|
105 |
thread['subscription'] = False
|
104 |
thread['subscription'] = False
|
106 |
M.session.artifact_orm_session._get().skip_mod_date = True
|
105 |
M.session.artifact_orm_session._get().skip_mod_date = True
|
107 |
redirect(request.referer)
|
106 |
redirect(request.referer)
|
108 |
|
107 |
|
109 |
@without_trailing_slash
|
108 |
def get_feed(self, project, app, user):
|
110 |
@expose()
|
109 |
"""Return a :class:`allura.controllers.feed.Feed` object describing
|
111 |
@validate(dict(
|
110 |
the xml feed for this controller.
|
112 |
since=DateTimeConverter(if_empty=None),
|
111 |
|
113 |
until=DateTimeConverter(if_empty=None),
|
112 |
Overrides :meth:`allura.controllers.feed.FeedController.get_feed`.
|
114 |
page=validators.Int(if_empty=None),
|
113 |
|
115 |
limit=validators.Int(if_empty=None)))
|
114 |
"""
|
116 |
def feed(self, since=None, until=None, page=None, limit=None, **kw):
|
115 |
return Feed(
|
117 |
if request.environ['PATH_INFO'].endswith('.atom'):
|
|
|
118 |
feed_type = 'atom'
|
|
|
119 |
else:
|
|
|
120 |
feed_type = 'rss'
|
|
|
121 |
title = 'Recent posts to %s' % self.discussion.name
|
|
|
122 |
feed = M.Feed.feed(
|
|
|
123 |
dict(ref_id={'$in': [t.index_id() for t in self.discussion.threads]}),
|
116 |
dict(ref_id={'$in': [t.index_id() for t in self.discussion.threads]}),
|
124 |
feed_type,
|
117 |
'Recent posts to %s' % self.discussion.name,
|
125 |
title,
|
|
|
126 |
self.discussion.url(),
|
118 |
self.discussion.url())
|
127 |
title,
|
119 |
|
128 |
since, until, page, limit)
|
|
|
129 |
response.headers['Content-Type'] = ''
|
|
|
130 |
response.content_type = 'application/xml'
|
|
|
131 |
return feed.writeString('utf-8')
|
|
|
132 |
|
120 |
|
133 |
class AppDiscussionController(DiscussionController):
|
121 |
class AppDiscussionController(DiscussionController):
|
134 |
|
122 |
|
135 |
@LazyProperty
|
123 |
@LazyProperty
|
136 |
def discussion(self):
|
124 |
def discussion(self):
|
|
... |
|
... |
154 |
id=unquote(id)
|
142 |
id=unquote(id)
|
155 |
return self.ThreadController(self._discussion_controller, id), remainder
|
143 |
return self.ThreadController(self._discussion_controller, id), remainder
|
156 |
else:
|
144 |
else:
|
157 |
raise exc.HTTPNotFound()
|
145 |
raise exc.HTTPNotFound()
|
158 |
|
146 |
|
159 |
class ThreadController(BaseController):
|
147 |
class ThreadController(BaseController, FeedController):
|
160 |
__metaclass__=h.ProxiedAttrMeta
|
148 |
__metaclass__=h.ProxiedAttrMeta
|
161 |
M=h.attrproxy('_discussion_controller', 'M')
|
149 |
M=h.attrproxy('_discussion_controller', 'M')
|
162 |
W=h.attrproxy('_discussion_controller', 'W')
|
150 |
W=h.attrproxy('_discussion_controller', 'W')
|
163 |
ThreadController=h.attrproxy('_discussion_controller', 'ThreadController')
|
151 |
ThreadController=h.attrproxy('_discussion_controller', 'ThreadController')
|
164 |
PostController=h.attrproxy('_discussion_controller', 'PostController')
|
152 |
PostController=h.attrproxy('_discussion_controller', 'PostController')
|
|
... |
|
... |
168 |
require_access(self.thread, 'read')
|
156 |
require_access(self.thread, 'read')
|
169 |
if self.thread.ref:
|
157 |
if self.thread.ref:
|
170 |
require_access(self.thread.ref.artifact, 'read')
|
158 |
require_access(self.thread.ref.artifact, 'read')
|
171 |
|
159 |
|
172 |
def __init__(self, discussion_controller, thread_id):
|
160 |
def __init__(self, discussion_controller, thread_id):
|
173 |
setattr(self, 'feed.rss', self.feed)
|
|
|
174 |
setattr(self, 'feed.atom', self.feed)
|
|
|
175 |
self._discussion_controller = discussion_controller
|
161 |
self._discussion_controller = discussion_controller
|
176 |
self.discussion = discussion_controller.discussion
|
162 |
self.discussion = discussion_controller.discussion
|
177 |
self.thread = self.M.Thread.query.get(_id=thread_id)
|
163 |
self.thread = self.M.Thread.query.get(_id=thread_id)
|
178 |
if not self.thread:
|
164 |
if not self.thread:
|
179 |
raise exc.HTTPNotFound
|
165 |
raise exc.HTTPNotFound
|
|
... |
|
... |
235 |
require_access(self.thread, 'moderate')
|
221 |
require_access(self.thread, 'moderate')
|
236 |
self.thread.spam()
|
222 |
self.thread.spam()
|
237 |
flash('Thread flagged as spam.')
|
223 |
flash('Thread flagged as spam.')
|
238 |
redirect(self.discussion.url())
|
224 |
redirect(self.discussion.url())
|
239 |
|
225 |
|
240 |
@without_trailing_slash
|
226 |
def get_feed(self, project, app, user):
|
241 |
@expose()
|
227 |
"""Return a :class:`allura.controllers.feed.Feed` object describing
|
242 |
@validate(dict(
|
228 |
the xml feed for this controller.
|
243 |
since=DateTimeConverter(if_empty=None),
|
229 |
|
244 |
until=DateTimeConverter(if_empty=None),
|
230 |
Overrides :meth:`allura.controllers.feed.FeedController.get_feed`.
|
245 |
page=validators.Int(if_empty=None),
|
231 |
|
246 |
limit=validators.Int(if_empty=None)))
|
232 |
"""
|
247 |
def feed(self, since=None, until=None, page=None, limit=None, **kw):
|
233 |
return Feed(
|
248 |
if request.environ['PATH_INFO'].endswith('.atom'):
|
|
|
249 |
feed_type = 'atom'
|
|
|
250 |
else:
|
|
|
251 |
feed_type = 'rss'
|
|
|
252 |
title = 'Recent posts to %s' % (self.thread.subject or '(no subject)')
|
|
|
253 |
feed = M.Feed.feed(
|
|
|
254 |
dict(ref_id=self.thread.index_id()),
|
234 |
dict(ref_id=self.thread.index_id()),
|
255 |
feed_type,
|
235 |
'Recent posts to %s' % (self.thread.subject or '(no subject)'),
|
256 |
title,
|
|
|
257 |
self.thread.url(),
|
236 |
self.thread.url())
|
258 |
title,
|
237 |
|
259 |
since, until, page, limit)
|
|
|
260 |
response.headers['Content-Type'] = ''
|
|
|
261 |
response.content_type = 'application/xml'
|
|
|
262 |
return feed.writeString('utf-8')
|
|
|
263 |
|
238 |
|
264 |
class PostController(BaseController):
|
239 |
class PostController(BaseController):
|
265 |
__metaclass__=h.ProxiedAttrMeta
|
240 |
__metaclass__=h.ProxiedAttrMeta
|
266 |
M=h.attrproxy('_discussion_controller', 'M')
|
241 |
M=h.attrproxy('_discussion_controller', 'M')
|
267 |
W=h.attrproxy('_discussion_controller', 'W')
|
242 |
W=h.attrproxy('_discussion_controller', 'W')
|