some refactor
This commit is contained in:
@@ -64,7 +64,7 @@ def ajax_content_response(request, course_id, content, template_name):
|
||||
def create_thread(request, course_id, commentable_id):
|
||||
post = request.POST
|
||||
thread = cc.Thread(**extract(post, ['body', 'title', 'tags']))
|
||||
thread.update_attributes({
|
||||
thread.update_attributes(**{
|
||||
'anonymous' : post.get('anonymous', 'false').lower() == 'true',
|
||||
'commentable_id' : commentable_id,
|
||||
'course_id' : course_id,
|
||||
@@ -94,7 +94,7 @@ def update_thread(request, course_id, thread_id):
|
||||
def _create_comment(request, course_id, thread_id=None, parent_id=None):
|
||||
post = request.POST
|
||||
comment = cc.Comment(**extract(post, ['body']))
|
||||
comment.update_attributes({
|
||||
comment.update_attributes(**{
|
||||
'anonymous' : post.get('anonymous', 'false').lower() == 'true',
|
||||
'user_id' : request.user.id,
|
||||
'course_id' : course_id,
|
||||
|
||||
@@ -12,13 +12,14 @@ from courseware.courses import get_course_with_access
|
||||
from dateutil.tz import tzlocal
|
||||
from datehelper import time_ago_in_words
|
||||
|
||||
import django_comment_client.utils as utils
|
||||
from urllib import urlencode
|
||||
from django_comment_client.permissions import check_permissions_by_view
|
||||
from django_comment_client.utils import merge_dict, extract, strip_none
|
||||
|
||||
import json
|
||||
import comment_client as cc
|
||||
import dateutil
|
||||
import django_comment_client.utils as utils
|
||||
import comment_client as cc
|
||||
|
||||
|
||||
THREADS_PER_PAGE = 5
|
||||
@@ -65,11 +66,8 @@ def render_discussion(request, course_id, threads, *args, **kwargs):
|
||||
'user': (lambda: reverse('django_comment_client.forum.views.user_profile', args=[course_id, user_id])),
|
||||
}[discussion_type]()
|
||||
|
||||
print "start annotating"
|
||||
annotated_content_infos = map(lambda x: utils.get_annotated_content_infos(course_id, x, request.user), threads)
|
||||
print "start merging annotations"
|
||||
annotated_content_info = reduce(utils.merge_dict, annotated_content_infos, {})
|
||||
print "finished annotating"
|
||||
annotated_content_info = reduce(merge_dict, annotated_content_infos, {})
|
||||
|
||||
context = {
|
||||
'threads': threads,
|
||||
@@ -82,7 +80,7 @@ def render_discussion(request, course_id, threads, *args, **kwargs):
|
||||
'pages_nearby_delta': PAGES_NEARBY_DELTA,
|
||||
'discussion_type': discussion_type,
|
||||
'base_url': base_url,
|
||||
'query_params': utils.strip_none(utils.extract(query_params, ['page', 'sort_key', 'sort_order', 'tags', 'text'])),
|
||||
'query_params': strip_none(extract(query_params, ['page', 'sort_key', 'sort_order', 'tags', 'text'])),
|
||||
'annotated_content_info': json.dumps(annotated_content_info),
|
||||
}
|
||||
context = dict(context.items() + query_params.items())
|
||||
@@ -98,17 +96,21 @@ def render_user_discussion(*args, **kwargs):
|
||||
return render_discussion(discussion_type='user', *args, **kwargs)
|
||||
|
||||
def get_threads(request, course_id, discussion_id=None):
|
||||
query_params = {
|
||||
'page': request.GET.get('page', 1),
|
||||
'per_page': THREADS_PER_PAGE, #TODO maybe change this later
|
||||
'sort_key': request.GET.get('sort_key', 'activity'),
|
||||
'sort_order': request.GET.get('sort_order', 'desc'),
|
||||
'text': request.GET.get('text', ''),
|
||||
'tags': request.GET.get('tags', ''),
|
||||
|
||||
default_query_params = {
|
||||
'page': 1,
|
||||
'per_page': THREADS_PER_PAGE,
|
||||
'sort_key': 'activity',
|
||||
'sort_order': 'desc',
|
||||
'text': '',
|
||||
'tags': '',
|
||||
'commentable_id': discussion_id,
|
||||
'course_id': course_id,
|
||||
}
|
||||
|
||||
query_params = merge_dict(default_query_params,
|
||||
strip_none(extract(request.GET, ['page', 'sort_key', 'sort_order', 'text', 'tags'])))
|
||||
|
||||
threads, page, num_pages = cc.Thread.search(query_params)
|
||||
|
||||
query_params['page'] = page
|
||||
@@ -138,7 +140,6 @@ def forum_form_discussion(request, course_id):
|
||||
threads, query_params = get_threads(request, course_id)
|
||||
content = render_forum_discussion(request, course_id, threads, discussion_id=_general_discussion_id(course_id), query_params=query_params)
|
||||
|
||||
|
||||
recent_active_threads = cc.search_recent_active_threads(
|
||||
course_id,
|
||||
recursive=False,
|
||||
@@ -159,6 +160,7 @@ def forum_form_discussion(request, course_id):
|
||||
'recent_active_threads': recent_active_threads,
|
||||
'trending_tags': trending_tags,
|
||||
}
|
||||
print "start rendering.."
|
||||
return render_to_response('discussion/index.html', context)
|
||||
|
||||
def render_single_thread(request, discussion_id, course_id, thread_id):
|
||||
@@ -209,14 +211,14 @@ def single_thread(request, course_id, discussion_id, thread_id):
|
||||
def user_profile(request, course_id, user_id):
|
||||
|
||||
course = get_course_with_access(request.user, course_id, 'load')
|
||||
discussion_user = cc.User(id=user_id, course_id=course_id)
|
||||
profiled_user = cc.User(id=user_id, course_id=course_id)
|
||||
|
||||
query_params = {
|
||||
'page': request.GET.get('page', 1),
|
||||
'per_page': THREADS_PER_PAGE, # more than threads_per_page to show more activities
|
||||
}
|
||||
|
||||
threads, page, num_pages = discussion_user.active_threads(query_params)
|
||||
threads, page, num_pages = profiled_user.active_threads(query_params)
|
||||
|
||||
query_params['page'] = page
|
||||
query_params['num_pages'] = num_pages
|
||||
@@ -230,7 +232,7 @@ def user_profile(request, course_id, user_id):
|
||||
'course': course,
|
||||
'user': request.user,
|
||||
'django_user': User.objects.get(id=user_id),
|
||||
'discussion_user': discussion_user.to_dict(),
|
||||
'profiled_user': profiled_user.to_dict(),
|
||||
'content': content,
|
||||
}
|
||||
|
||||
|
||||
@@ -20,9 +20,12 @@ def extract(dic, keys):
|
||||
return {k: dic.get(k) for k in keys}
|
||||
|
||||
def strip_none(dic):
|
||||
def _is_none(v):
|
||||
return v is None or (isinstance(v, str) and len(v.strip()) == 0)
|
||||
return dict([(k, v) for k, v in dic.iteritems() if not _is_none(v)])
|
||||
return dict([(k, v) for k, v in dic.iteritems() if v is not None])
|
||||
|
||||
def strip_blank(dic):
|
||||
def _is_blank(v):
|
||||
return isinstance(v, str) and len(v.strip()) == 0
|
||||
return dict([(k, v) for k, v in dic.iteritems() if not _is_blank(v)])
|
||||
|
||||
def merge_dict(dic1, dic2):
|
||||
return dict(dic1.items() + dic2.items())
|
||||
|
||||
@@ -41,7 +41,7 @@ PERFSTATS = False
|
||||
# Features
|
||||
MITX_FEATURES = {
|
||||
'SAMPLE' : False,
|
||||
'USE_DJANGO_PIPELINE' : True,
|
||||
'USE_DJANGO_PIPELINE' : False,
|
||||
'DISPLAY_HISTOGRAMS_TO_STAFF' : True,
|
||||
'REROUTE_ACTIVATION_EMAIL' : False, # nonempty string = address for all activation emails
|
||||
'DEBUG_LEVEL' : 0, # 0 = lowest level, least verbose, 255 = max level, most verbose
|
||||
|
||||
@@ -30,8 +30,8 @@ class Thread(models.Model):
|
||||
'per_page': 20,
|
||||
'course_id': query_params['course_id'],
|
||||
'recursive': False}
|
||||
params = merge_dict(default_params, strip_none(query_params))
|
||||
if query_params['text'] or query_params['tags']:
|
||||
params = merge_dict(default_params, strip_blank(strip_none(query_params)))
|
||||
if query_params.get('text') or query_params.get('tags'):
|
||||
url = cls.url(action='search')
|
||||
else:
|
||||
url = cls.url(action='get_all', params=extract(params, 'commentable_id'))
|
||||
|
||||
@@ -2,9 +2,12 @@ import requests
|
||||
import json
|
||||
|
||||
def strip_none(dic):
|
||||
def _is_none(v):
|
||||
return v is None or (isinstance(v, str) and len(v.strip()) == 0)
|
||||
return dict([(k, v) for k, v in dic.iteritems() if not _is_none(v)])
|
||||
return dict([(k, v) for k, v in dic.iteritems() if v is not None])
|
||||
|
||||
def strip_blank(dic):
|
||||
def _is_blank(v):
|
||||
return isinstance(v, str) and len(v.strip()) == 0
|
||||
return dict([(k, v) for k, v in dic.iteritems() if not _is_blank(v)])
|
||||
|
||||
def extract(dic, keys):
|
||||
if isinstance(keys, str):
|
||||
|
||||
@@ -402,5 +402,5 @@ initializeFollowThread = (thread) ->
|
||||
$local(".admin-delete").remove()
|
||||
if not Discussion.getContentInfo id, 'can_openclose'
|
||||
$local(".discussion-openclose").remove()
|
||||
if not Discussion.getContentInfo id, 'can_vote'
|
||||
$local(".discussion-vote").css "visibility", "hidden"
|
||||
#if not Discussion.getContentInfo id, 'can_vote'
|
||||
# $local(".discussion-vote").css "visibility", "hidden"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<%namespace name="renderer" file="_thread.html"/>
|
||||
<%! from django.template.defaultfilters import escapejs %>
|
||||
|
||||
<section class="discussion forum-discussion" _id="${discussion_id}">
|
||||
|
||||
@@ -24,16 +23,4 @@
|
||||
% endif
|
||||
</section>
|
||||
|
||||
<%!
|
||||
def escape_quotes(text):
|
||||
return text.replace('\"', '\\\"').replace("\'", "\\\'")
|
||||
%>
|
||||
|
||||
<script type="text/javascript">
|
||||
var $$user_info = JSON.parse("${user_info | escapejs}");
|
||||
var $$course_id = "${course_id | escapejs}";
|
||||
if (typeof $$annotated_content_info === undefined || $$annotated_content_info === null) {
|
||||
var $$annotated_content_info = {};
|
||||
}
|
||||
$$annotated_content_info = $.extend($$annotated_content_info, JSON.parse("${annotated_content_info | escapejs}"));
|
||||
</script>
|
||||
<%include file="_js_data.html" />
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<%namespace name="renderer" file="_thread.html"/>
|
||||
<%! from django.template.defaultfilters import escapejs %>
|
||||
|
||||
<section class="discussion inline-discussion" _id="${discussion_id}">
|
||||
|
||||
@@ -14,11 +13,4 @@
|
||||
<%include file="_paginator.html" />
|
||||
</section>
|
||||
|
||||
<script type="text/javascript">
|
||||
var $$user_info = JSON.parse("${user_info | escapejs}");
|
||||
var $$course_id = "${course_id | escapejs}";
|
||||
if (typeof $$annotated_content_info === undefined || $$annotated_content_info === null) {
|
||||
var $$annotated_content_info = {};
|
||||
}
|
||||
$$annotated_content_info = $.extend($$annotated_content_info, JSON.parse("${annotated_content_info | escapejs}"));
|
||||
</script>
|
||||
<%include file="_js_data.html" />
|
||||
|
||||
10
lms/templates/discussion/_js_data.html
Normal file
10
lms/templates/discussion/_js_data.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<%! from django.template.defaultfilters import escapejs %>
|
||||
|
||||
<script type="text/javascript">
|
||||
var $$user_info = JSON.parse("${user_info | escapejs}");
|
||||
var $$course_id = "${course_id | escapejs}";
|
||||
if (typeof $$annotated_content_info === undefined || $$annotated_content_info === null) {
|
||||
var $$annotated_content_info = {};
|
||||
}
|
||||
$$annotated_content_info = $.extend($$annotated_content_info, JSON.parse("${annotated_content_info | escapejs}"));
|
||||
</script>
|
||||
@@ -1,33 +1,30 @@
|
||||
|
||||
<%namespace name='static' file='../static_content.html'/>
|
||||
|
||||
<!-- The configuration below is different from the main mathjax config because dollar signs make it easier
|
||||
to integrate with Markdown. -->
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [
|
||||
["\\(","\\)"],
|
||||
],
|
||||
displayMath: [
|
||||
["\\[","\\]"],
|
||||
]
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [
|
||||
["\\(","\\)"],
|
||||
],
|
||||
displayMath: [
|
||||
["\\[","\\]"],
|
||||
]
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
## This must appear after all mathjax-config blocks, so it is after the imports from the other templates.
|
||||
## It can't be run through static.url because MathJax uses crazy url introspection to do lazy loading of MathJax extension libraries
|
||||
<script type="text/javascript" src="/static/js/vendor/mathjax-MathJax-c9db6ac/MathJax.js?config=TeX-MML-AM_HTMLorMML-full"></script>
|
||||
<!---<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js"> </script>-->
|
||||
<script type="text/javascript" src="${static.url('js/split.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/jquery.ajaxfileupload.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/Markdown.Converter.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/Markdown.Sanitizer.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/Markdown.Editor.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/jquery.autocomplete.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/jquery.tagsinput.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/mustache.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/URI.min.js')}"></script>
|
||||
<link href="${static.url('css/vendor/jquery.tagsinput.css')}" rel="stylesheet" type="text/css">
|
||||
<link href="${static.url('css/vendor/jquery.autocomplete.css')}" rel="stylesheet" type="text/css">
|
||||
## This must appear after all mathjax-config blocks, so it is after the imports from the other templates.
|
||||
## It can't be run through static.url because MathJax uses crazy url introspection to do lazy loading of MathJax extension libraries
|
||||
<script type="text/javascript" src="/static/js/vendor/mathjax-MathJax-c9db6ac/MathJax.js?config=TeX-MML-AM_HTMLorMML-full"></script>
|
||||
<!---<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js"> </script>-->
|
||||
<script type="text/javascript" src="${static.url('js/split.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/jquery.ajaxfileupload.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/Markdown.Converter.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/Markdown.Sanitizer.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/Markdown.Editor.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/jquery.autocomplete.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/jquery.tagsinput.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/mustache.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/URI.min.js')}"></script>
|
||||
<link href="${static.url('css/vendor/jquery.tagsinput.css')}" rel="stylesheet" type="text/css">
|
||||
<link href="${static.url('css/vendor/jquery.autocomplete.css')}" rel="stylesheet" type="text/css">
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
<%namespace name="renderer" file="_thread.html"/>
|
||||
<%! from django.template.defaultfilters import escapejs %>
|
||||
|
||||
<section class="discussion" _id="${discussion_id}">
|
||||
<a class="discussion-title" href="javascript:void(0)">Discussion</a>
|
||||
${renderer.render_thread(course_id, thread, show_comments=True)}
|
||||
</section>
|
||||
|
||||
<script type="text/javascript">
|
||||
var $$user_info = JSON.parse("${user_info | escapejs}");
|
||||
var $$course_id = "${course_id | escapejs}";
|
||||
if (typeof $$annotated_content_info === undefined || $$annotated_content_info === null) {
|
||||
var $$annotated_content_info = {};
|
||||
}
|
||||
$$annotated_content_info = $.extend($$annotated_content_info, JSON.parse("${annotated_content_info | escapejs}"));
|
||||
</script>
|
||||
<%include file="_js_data.html" />
|
||||
|
||||
@@ -5,15 +5,23 @@
|
||||
<%! import urllib %>
|
||||
|
||||
<%!
|
||||
def user_id_with_anonymity(content):
|
||||
if content.get('anonymous', False):
|
||||
return ''
|
||||
def show_if(text, condition):
|
||||
if condition:
|
||||
return text
|
||||
else:
|
||||
return content['user_id']
|
||||
return ''
|
||||
%>
|
||||
|
||||
<%!
|
||||
def close_thread_text(content):
|
||||
if content.get('closed'):
|
||||
return 'Re-open thread'
|
||||
else:
|
||||
return 'Close thread'
|
||||
%>
|
||||
|
||||
<%def name="render_thread(course_id, thread, show_comments=False)">
|
||||
<div class="thread" _id="${thread['id']}" _discussion_id="${thread['commentable_id']}" _author_id="${user_id_with_anonymity(thread)}">
|
||||
<div class="thread" _id="${thread['id']}" _discussion_id="${thread['commentable_id']}" _author_id="${show_if(thread['user_id'], thread.get('anonymous'))}">
|
||||
${render_content(thread, "thread", show_comments=show_comments)}
|
||||
% if show_comments:
|
||||
${render_comments(thread.get('children', []))}
|
||||
@@ -22,11 +30,7 @@
|
||||
</%def>
|
||||
|
||||
<%def name="render_comment(comment)">
|
||||
% if comment['endorsed']:
|
||||
<div class="comment endorsed" _id="${comment['id']}" _author_id="${user_id_with_anonymity(comment)}">
|
||||
% else:
|
||||
<div class="comment" _id="${comment['id']}" _author_id="${user_id_with_anonymity(comment)}">
|
||||
% endif
|
||||
<div class="comment ${show_if('endorsed', comment.get('endorsed'))}" _id="${comment['id']}" _author_id="${show_if(comment['user_id'], comment.get('anonymous'))}">
|
||||
${render_content(comment, "comment")}
|
||||
<div class="comments">
|
||||
${render_comments(comment.get('children', []))}
|
||||
@@ -45,7 +49,6 @@
|
||||
<%def name="render_content(content, type, **kwargs)">
|
||||
<div class="discussion-content">
|
||||
<div class="discussion-content-wrapper">
|
||||
|
||||
${render_vote(content)}
|
||||
<div class="discussion-right-wrapper">
|
||||
<ul class="admin-actions">
|
||||
@@ -55,24 +58,13 @@
|
||||
<li><a href="javascript:void(0)" class="admin-edit">Edit</a></li>
|
||||
<li><a href="javascript:void(0)" class="admin-delete">Delete</a></li>
|
||||
% if type == "thread":
|
||||
<li>
|
||||
% if content['closed']:
|
||||
<a class="discussion-openclose" id="discussion-openclose-${content['id']}" href="javascript:void(0);">Re-open thread</a>
|
||||
% else:
|
||||
<a class="discussion-openclose" id="discussion-openclose-${content['id']}" href="javascript:void(0);">Close thread</a>
|
||||
% endif
|
||||
</li>
|
||||
<li><a class="discussion-openclose" id="discussion-openclose-${content['id']}" href="javascript:void(0);">${close_thread_text(content)}</a></li>
|
||||
% endif
|
||||
</ul>
|
||||
|
||||
${render_title(content, type, **kwargs)}
|
||||
<div class="discussion-content-view">
|
||||
<a name="${content['id']}" style="width: 0; height: 0; padding: 0; border: none;"></a>
|
||||
% if content.get('highlighted_body', None):
|
||||
<div class="content-body ${type}-body" id="content-body-${content['id']}">${content['highlighted_body'] | h}</div>
|
||||
% else:
|
||||
<div class="content-body ${type}-body" id="content-body-${content['id']}">${content['body'] | h}</div>
|
||||
% endif
|
||||
<div class="content-body ${type}-body" id="content-body-${content['id']}">${(content.get('highlighted_body') or content['body']) | h}</div>
|
||||
<div class="content-raw-body ${type}-raw-body" style="display: none">${content['body'] | h}</div>
|
||||
${render_tags(content, type, **kwargs)}
|
||||
${render_bottom_bar(content, type, **kwargs)}
|
||||
@@ -84,11 +76,7 @@
|
||||
|
||||
<%def name="render_title(content, type, **kwargs)">
|
||||
% if type == "thread":
|
||||
% if content.get('highlighted_title', None):
|
||||
<a class="thread-title" name="${content['id']}" href="javascript:void(0)">${content['highlighted_title'] | h}</a>
|
||||
% else:
|
||||
<a class="thread-title" name="${content['id']}" href="javascript:void(0)">${content['title'] | h}</a>
|
||||
% endif
|
||||
<a class="thread-title" name="${content['id']}" href="javascript:void(0)">${(content.get('highlighted_title') or content['title']) | h}</a>
|
||||
<div class="thread-raw-title" style="display: none">${content['title']}</div>
|
||||
% endif
|
||||
</%def>
|
||||
@@ -110,7 +98,7 @@
|
||||
|
||||
<%def name="render_bottom_bar(content, type, **kwargs)">
|
||||
<div class="info">
|
||||
${render_info(content, type, **kwargs)}
|
||||
${render_info(content, type, **kwargs)}
|
||||
<ul class="discussion-actions">
|
||||
<li>${render_link("discussion-link discussion-reply discussion-reply-" + type, "Reply")}</li>
|
||||
<li><div class="follow-wrapper"></div></li>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<%namespace name="renderer" file="_thread.html"/>
|
||||
<%! from django.template.defaultfilters import escapejs %>
|
||||
|
||||
<section class="discussion user-active-discussion">
|
||||
|
||||
@@ -14,11 +13,4 @@
|
||||
<%include file="_paginator.html" />
|
||||
</section>
|
||||
|
||||
<script type="text/javascript">
|
||||
var $$user_info = JSON.parse("${user_info | escapejs}");
|
||||
var $$course_id = "${course_id | escapejs}";
|
||||
if (typeof $$annotated_content_info === undefined || $$annotated_content_info === null) {
|
||||
var $$annotated_content_info = {};
|
||||
}
|
||||
$$annotated_content_info = $.extend($$annotated_content_info, JSON.parse("${annotated_content_info | escapejs}"));
|
||||
</script>
|
||||
<%include file="_js_data.html" />
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
<%! from django_comment_client.utils import pluralize %>
|
||||
<%! from django_comment_client.permissions import has_permission, check_permissions_by_view %>
|
||||
<%! from operator import attrgetter %>
|
||||
|
||||
|
||||
<div class="user-profile">
|
||||
<%
|
||||
role_names = sorted(map(lambda x: x.name, django_user.roles.all()))
|
||||
role_names = sorted(map(attrgetter('name'), django_user.roles.all()))
|
||||
%>
|
||||
<div class="sidebar-username">${django_user.username}</div>
|
||||
<div class="sidebar-user-roles">
|
||||
${", ".join(role_names)}
|
||||
</div>
|
||||
<div class="sidebar-threads-count"><span>${discussion_user['threads_count']}</span> ${pluralize('discussion', discussion_user['threads_count'])} started</div>
|
||||
<div class="sidebar-comments-count"><span>${discussion_user['comments_count']}</span> ${pluralize('comment', discussion_user['comments_count'])}</div>
|
||||
<div class="sidebar-threads-count"><span>${profiled_user['threads_count']}</span> ${pluralize('discussion', profiled_user['threads_count'])} started</div>
|
||||
<div class="sidebar-comments-count"><span>${profiled_user['comments_count']}</span> ${pluralize('comment', profiled_user['comments_count'])}</div>
|
||||
% if check_permissions_by_view(user, course.id, content=None, name='update_moderator_status'):
|
||||
% if "Moderator" in role_names:
|
||||
<a href="javascript:void(0)" class="sidebar-revoke-moderator-button">Revoke Moderator provileges</a>
|
||||
|
||||
Reference in New Issue
Block a user