|
a/Allura/allura/lib/macro.py |
|
b/Allura/allura/lib/macro.py |
|
... |
|
... |
16 |
# under the License.
|
16 |
# under the License.
|
17 |
|
17 |
|
18 |
import cgi
|
18 |
import cgi
|
19 |
import random
|
19 |
import random
|
20 |
import shlex
|
20 |
import shlex
|
21 |
import string
|
|
|
22 |
import logging
|
21 |
import logging
|
23 |
import traceback
|
22 |
import traceback
|
24 |
from operator import attrgetter
|
23 |
from operator import attrgetter
|
25 |
|
24 |
|
26 |
import pymongo
|
25 |
import pymongo
|
27 |
import jinja2
|
|
|
28 |
from pylons import tmpl_context as c, app_globals as g
|
26 |
from pylons import tmpl_context as c, app_globals as g
|
29 |
from pylons import request
|
27 |
from pylons import request
|
30 |
from paste.deploy.converters import asint
|
28 |
from paste.deploy.converters import asint
|
31 |
from urlparse import urljoin
|
|
|
32 |
|
29 |
|
33 |
from . import helpers as h
|
30 |
from . import helpers as h
|
34 |
from . import security
|
31 |
from . import security
|
35 |
|
32 |
|
36 |
log = logging.getLogger(__name__)
|
33 |
log = logging.getLogger(__name__)
|
|
... |
|
... |
80 |
if context is None or context == self._context:
|
77 |
if context is None or context == self._context:
|
81 |
return macro
|
78 |
return macro
|
82 |
else:
|
79 |
else:
|
83 |
return None
|
80 |
return None
|
84 |
|
81 |
|
85 |
template_neighborhood_feeds = string.Template('''
|
|
|
86 |
<div class="neighborhood_feed_entry">
|
|
|
87 |
<h3><a href="$href">$title</a></h3>
|
|
|
88 |
<p>
|
|
|
89 |
by <em>$author</em>
|
|
|
90 |
<small>$ago</small>
|
|
|
91 |
</p>
|
|
|
92 |
<p>$description</p>
|
|
|
93 |
</div>
|
|
|
94 |
''')
|
|
|
95 |
@macro('neighborhood-wiki')
|
82 |
@macro('neighborhood-wiki')
|
96 |
def neighborhood_feeds(tool_name, max_number=5, sort='pubdate'):
|
83 |
def neighborhood_feeds(tool_name, max_number=5, sort='pubdate'):
|
97 |
from allura import model as M
|
84 |
from allura import model as M
|
|
|
85 |
from allura.lib.widgets.macros import NeighborhoodFeeds
|
98 |
feed = M.Feed.query.find(
|
86 |
feed = M.Feed.query.find(
|
99 |
dict(
|
87 |
dict(
|
100 |
tool_name=tool_name,
|
88 |
tool_name=tool_name,
|
101 |
neighborhood_id=c.project.neighborhood._id))
|
89 |
neighborhood_id=c.project.neighborhood._id))
|
102 |
feed = feed.sort(sort, pymongo.DESCENDING).limit(int(max_number)).all()
|
90 |
feed = feed.sort(sort, pymongo.DESCENDING).limit(int(max_number)).all()
|
103 |
output = '\n'.join(
|
91 |
output = ((dict(
|
104 |
template_neighborhood_feeds.substitute(dict(
|
|
|
105 |
href=item.link,
|
92 |
href=item.link,
|
106 |
title=item.title,
|
93 |
title=item.title,
|
107 |
author=item.author_name,
|
94 |
author=item.author_name,
|
108 |
ago=h.ago(item.pubdate),
|
95 |
ago=h.ago(item.pubdate),
|
109 |
description=item.description))
|
96 |
description=g.markdown.convert(item.description)))
|
110 |
for item in feed)
|
97 |
for item in feed)
|
111 |
return output
|
98 |
feeds = NeighborhoodFeeds(feeds=output)
|
|
|
99 |
g.resource_manager.register(feeds)
|
|
|
100 |
response = feeds.display(feeds=output)
|
|
|
101 |
return response
|
112 |
|
102 |
|
113 |
template_neighborhood_blog_posts = string.Template('''
|
|
|
114 |
<div class="neighborhood_feed_entry">
|
|
|
115 |
<h3><a href="$href">$title</a></h3>
|
|
|
116 |
<p>
|
|
|
117 |
by <em>$author</em>
|
|
|
118 |
<small>$ago</small>
|
|
|
119 |
</p>
|
|
|
120 |
$description
|
|
|
121 |
</div>
|
|
|
122 |
''')
|
|
|
123 |
@macro('neighborhood-wiki')
|
103 |
@macro('neighborhood-wiki')
|
124 |
def neighborhood_blog_posts(max_number=5, sort='timestamp', summary=False):
|
104 |
def neighborhood_blog_posts(max_number=5, sort='timestamp', summary=False):
|
125 |
from forgeblog import model as BM
|
105 |
from forgeblog import model as BM
|
|
|
106 |
from allura.lib.widgets.macros import BlogPosts
|
126 |
posts = BM.BlogPost.query.find(dict(
|
107 |
posts = BM.BlogPost.query.find(dict(
|
127 |
neighborhood_id=c.project.neighborhood._id,
|
108 |
neighborhood_id=c.project.neighborhood._id,
|
128 |
state='published'))
|
109 |
state='published'))
|
129 |
posts = posts.sort(sort, pymongo.DESCENDING).limit(int(max_number)).all()
|
110 |
posts = posts.sort(sort, pymongo.DESCENDING).limit(int(max_number)).all()
|
130 |
output = '\n'.join(
|
111 |
output = ((dict(
|
131 |
template_neighborhood_blog_posts.substitute(dict(
|
|
|
132 |
href=post.url(),
|
112 |
href=post.url(),
|
133 |
title=post.title,
|
113 |
title=post.title,
|
134 |
author=post.author().display_name,
|
114 |
author=post.author().display_name,
|
135 |
ago=h.ago(post.timestamp),
|
115 |
ago=h.ago(post.timestamp),
|
136 |
description=summary and ' ' or g.markdown.convert(post.text)))
|
116 |
description=summary and ' ' or g.markdown.convert(post.text)))
|
137 |
for post in posts if post.app and
|
117 |
for post in posts if post.app and
|
138 |
security.has_access(post, 'read', project=post.app.project)() and
|
118 |
security.has_access(post, 'read', project=post.app.project)() and
|
139 |
security.has_access(post.app.project, 'read', project=post.app.project)())
|
119 |
security.has_access(post.app.project, 'read', project=post.app.project)())
|
140 |
return output
|
120 |
|
|
|
121 |
posts = BlogPosts(posts=output)
|
|
|
122 |
g.resource_manager.register(posts)
|
|
|
123 |
response = posts.display(posts=output)
|
|
|
124 |
return response
|
141 |
|
125 |
|
142 |
@macro()
|
126 |
@macro()
|
143 |
def project_blog_posts(max_number=5, sort='timestamp', summary=False, mount_point=None):
|
127 |
def project_blog_posts(max_number=5, sort='timestamp', summary=False, mount_point=None):
|
144 |
from forgeblog import model as BM
|
128 |
from forgeblog import model as BM
|
|
|
129 |
from allura.lib.widgets.macros import BlogPosts
|
145 |
app_config_ids = []
|
130 |
app_config_ids = []
|
146 |
for conf in c.project.app_configs:
|
131 |
for conf in c.project.app_configs:
|
147 |
if conf.tool_name.lower() == 'blog' and (mount_point is None or conf.options.mount_point==mount_point):
|
132 |
if conf.tool_name.lower() == 'blog' and (mount_point is None or conf.options.mount_point==mount_point):
|
148 |
app_config_ids.append(conf._id)
|
133 |
app_config_ids.append(conf._id)
|
149 |
posts = BM.BlogPost.query.find({'state':'published','app_config_id':{'$in':app_config_ids}})
|
134 |
posts = BM.BlogPost.query.find({'state':'published','app_config_id':{'$in':app_config_ids}})
|
150 |
posts = posts.sort(sort, pymongo.DESCENDING).limit(int(max_number)).all()
|
135 |
posts = posts.sort(sort, pymongo.DESCENDING).limit(int(max_number)).all()
|
151 |
output = '\n'.join(
|
136 |
output = ((dict(
|
152 |
template_neighborhood_blog_posts.substitute(dict(
|
|
|
153 |
href=post.url(),
|
137 |
href=post.url(),
|
154 |
title=post.title,
|
138 |
title=post.title,
|
155 |
author=post.author().display_name,
|
139 |
author=post.author().display_name,
|
156 |
ago=h.ago(post.timestamp),
|
140 |
ago=h.ago(post.timestamp),
|
157 |
description=summary and ' ' or g.markdown.convert(post.text)))
|
141 |
description=summary and ' ' or g.markdown.convert(post.text)))
|
158 |
for post in posts if security.has_access(post, 'read', project=post.app.project)() and
|
142 |
for post in posts if security.has_access(post, 'read', project=post.app.project)() and
|
159 |
security.has_access(post.app.project, 'read', project=post.app.project)())
|
143 |
security.has_access(post.app.project, 'read', project=post.app.project)())
|
160 |
return output
|
144 |
posts = BlogPosts(posts=output)
|
|
|
145 |
g.resource_manager.register(posts)
|
|
|
146 |
response = posts.display(posts=output)
|
|
|
147 |
return response
|
161 |
|
148 |
|
162 |
def get_projects_for_macro(category=None, display_mode='grid', sort='last_updated',
|
149 |
def get_projects_for_macro(category=None, display_mode='grid', sort='last_updated',
|
163 |
show_total=False, limit=100, labels='', award='', private=False,
|
150 |
show_total=False, limit=100, labels='', award='', private=False,
|
164 |
columns=1, show_proj_icon=True, show_download_button=True, show_awards_banner=True,
|
151 |
columns=1, show_proj_icon=True, show_download_button=True, show_awards_banner=True,
|
165 |
grid_view_tools='',
|
152 |
grid_view_tools='',
|
|
... |
|
... |
350 |
if '://' in src:
|
337 |
if '://' in src:
|
351 |
return '<img src="%s" %s/>' % (src, ' '.join(attrs))
|
338 |
return '<img src="%s" %s/>' % (src, ' '.join(attrs))
|
352 |
else:
|
339 |
else:
|
353 |
return '<img src="./attachment/%s" %s/>' % (src, ' '.join(attrs))
|
340 |
return '<img src="./attachment/%s" %s/>' % (src, ' '.join(attrs))
|
354 |
|
341 |
|
355 |
|
|
|
356 |
template_project_admins = string.Template('<li><a href="$url">$name</a></li>')
|
|
|
357 |
@macro()
|
342 |
@macro()
|
358 |
def project_admins():
|
343 |
def project_admins():
|
359 |
admins = c.project.users_with_role('Admin')
|
344 |
admins = c.project.users_with_role('Admin')
|
360 |
output = ''.join(
|
345 |
from allura.lib.widgets.macros import ProjectAdmins
|
361 |
template_project_admins.substitute(dict(
|
346 |
output = ((dict(
|
362 |
url=user.url(),
|
347 |
url=user.url(),
|
363 |
name=jinja2.escape(user.display_name)))
|
348 |
name=user.display_name))
|
364 |
for user in admins)
|
349 |
for user in admins)
|
365 |
return u'<h6>Project Admins:</h6><ul class="md-users-list">{0}</ul>'.format(output)
|
350 |
users = ProjectAdmins(users=output)
|
|
|
351 |
g.resource_manager.register(users)
|
|
|
352 |
response = users.display(users=output)
|
|
|
353 |
return response
|
366 |
|
354 |
|
367 |
template_members = string.Template('<li><a href="$url">$name</a>$admin</li>')
|
|
|
368 |
@macro()
|
355 |
@macro()
|
369 |
def members(limit=20):
|
356 |
def members(limit=20):
|
|
|
357 |
from allura.lib.widgets.macros import Members
|
370 |
limit = asint(limit)
|
358 |
limit = asint(limit)
|
371 |
admins = set(c.project.users_with_role('Admin'))
|
359 |
admins = set(c.project.users_with_role('Admin'))
|
372 |
members = sorted(c.project.users(), key=attrgetter('display_name'))
|
360 |
members = sorted(c.project.users(), key=attrgetter('display_name'))
|
373 |
output = ''.join(
|
361 |
output = [dict(
|
374 |
template_members.substitute(dict(
|
|
|
375 |
url=user.url(),
|
362 |
url=user.url(),
|
376 |
name=jinja2.escape(user.display_name),
|
363 |
name=user.display_name,
|
377 |
admin=' (admin)' if user in admins else '',
|
364 |
admin=' (admin)' if user in admins else '',
|
378 |
))
|
365 |
)
|
379 |
for user in members[:limit])
|
366 |
for user in members[:limit]]
|
|
|
367 |
|
380 |
if len(members) > limit:
|
368 |
over_limit = len(members) > limit
|
381 |
output = output + '<li class="md-users-list-more"><a href="%s_members">All Members</a></li>' % c.project.url()
|
369 |
users = Members(users=output, over_limit=over_limit)
|
382 |
return u'<h6>Project Members:</h6><ul class="md-users-list">{0}</ul>'.format(output)
|
370 |
g.resource_manager.register(users)
|
|
|
371 |
response = users.display(users=output, over_limit=over_limit)
|
|
|
372 |
return response
|
|
|
373 |
|