You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by br...@apache.org on 2018/11/08 21:53:49 UTC
[08/10] allura git commit: [#8253] Refactor codes and customizable
emojis for reactions
[#8253] Refactor codes and customizable emojis for reactions
Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/8d3b43b1
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/8d3b43b1
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/8d3b43b1
Branch: refs/heads/master
Commit: 8d3b43b10497c02e31d7fe67c95a508421860644
Parents: de72730
Author: Shalitha <sh...@gmail.com>
Authored: Thu Nov 1 15:18:50 2018 +0530
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Nov 8 21:53:25 2018 +0000
----------------------------------------------------------------------
Allura/allura/controllers/discuss.py | 16 ++---
Allura/allura/lib/app_globals.py | 5 ++
Allura/allura/lib/utils.py | 12 ++++
Allura/allura/lib/widgets/discuss.py | 72 ++++++++++++++++++++
Allura/allura/model/artifact.py | 57 +++++++---------
Allura/allura/public/nf/js/allura-base.js | 69 -------------------
.../allura/templates/widgets/post_widget.html | 21 +-----
Allura/allura/tests/functional/test_discuss.py | 32 +++++----
8 files changed, 140 insertions(+), 144 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/allura/blob/8d3b43b1/Allura/allura/controllers/discuss.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/discuss.py b/Allura/allura/controllers/discuss.py
index f2ea923..1e5e30a 100644
--- a/Allura/allura/controllers/discuss.py
+++ b/Allura/allura/controllers/discuss.py
@@ -379,19 +379,15 @@ class PostController(BaseController):
'error' : 'no_permission'
}
status = 'ok'
- if r in self.post.reaction_list:
+ if r in utils.get_reaction_emoji_list():
self.post.post_reaction(r, c.user)
else:
status = 'error'
- return {
- 'status' : status,
- 'react_thumbs_up': self.post.react_thumbs_up,
- 'react_thumbs_down': self.post.react_thumbs_down,
- 'react_laugh': self.post.react_laugh,
- 'react_hooray': self.post.react_hooray,
- 'react_confused': self.post.react_confused,
- 'react_heart': self.post.react_heart
- }
+ emoji_unicode = {}
+ # Need send back unicode emojis too for rendering :+1: .. etc
+ for em_code in self.post.react_counts:
+ emoji_unicode[em_code] = g.emojize(em_code)
+ return dict(status=status, counts=self.post.react_counts, emoji_unicode=emoji_unicode)
def error_handler(self, *args, **kwargs):
redirect(request.referer)
http://git-wip-us.apache.org/repos/asf/allura/blob/8d3b43b1/Allura/allura/lib/app_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/app_globals.py b/Allura/allura/lib/app_globals.py
index ddcfa14..02980c1 100644
--- a/Allura/allura/lib/app_globals.py
+++ b/Allura/allura/lib/app_globals.py
@@ -34,6 +34,7 @@ import traceback
import activitystream
import pkg_resources
import markdown
+import emoji
import pygments
import pygments.lexers
import pygments.formatters
@@ -608,6 +609,10 @@ class Globals(object):
"image_height": logo['image_height']
}
+ def emojize(self, text):
+ """Coverts emoji codes to unicode emojis"""
+ return emoji.emojize(text, use_aliases=True)
+
class Icon(object):
http://git-wip-us.apache.org/repos/asf/allura/blob/8d3b43b1/Allura/allura/lib/utils.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/utils.py b/Allura/allura/lib/utils.py
index ccc19d2..07fd2a1 100644
--- a/Allura/allura/lib/utils.py
+++ b/Allura/allura/lib/utils.py
@@ -30,6 +30,7 @@ import magic
from itertools import groupby
import operator as op
import collections
+import emoji
import tg
import pylons
@@ -762,3 +763,14 @@ def umask(new_mask):
yield
finally:
os.umask(cur_mask)
+
+
+def get_reaction_emoji_list():
+ """ Get reactions emoji list from .ini file. If not defined there get fixed
+ default emoji list """
+ emo_list = tg.config.get('reactions.emoji_list')
+ if emo_list is None:
+ emo_list = [':+1:', ':-1:', ':smile:', ':tada:', ':confused:', ':heart:']
+ else:
+ emo_list = emo_list.split(',')
+ return emo_list
http://git-wip-us.apache.org/repos/asf/allura/blob/8d3b43b1/Allura/allura/lib/widgets/discuss.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/widgets/discuss.py b/Allura/allura/lib/widgets/discuss.py
index f7be446..9ff25f9 100644
--- a/Allura/allura/lib/widgets/discuss.py
+++ b/Allura/allura/lib/widgets/discuss.py
@@ -19,7 +19,10 @@ from formencode import validators as fev
import ew as ew_core
import ew.jinja2_ew as ew
+from pylons import app_globals as g
+from tg import config
+from allura.lib import utils
from allura.lib import validators as V
from allura.lib.widgets import form_fields as ffw
from allura.lib.widgets import forms as ff
@@ -300,6 +303,15 @@ class Post(HierWidget):
attach_post=AttachPost(submit_text='Attach'),
attachment=Attachment())
+ def get_reaction_tooltip_content(self):
+ """Construct html content for the reaction tooltip"""
+ html = ''
+ for em in utils.get_reaction_emoji_list():
+ emoji_u = g.emojize(em)
+ html += '<span onclick="reactComment(\'` + btnId + `\', \'%s\')">` + twemoji.parse(\'%s\') + `</span>' % \
+ (em, emoji_u)
+ return html
+
def resources(self):
for r in super(Post, self).resources():
yield r
@@ -427,6 +439,66 @@ class Post(HierWidget):
});
}());
''')
+
+ yield ew.JSScript('''
+ // Reaction support
+ $(function(){
+
+ $('.reaction-button').tooltipster({
+ animation: 'fade',
+ delay: 200,
+ theme: 'tooltipster-default',
+ trigger: 'click',
+ position: 'top',
+ iconCloning: false,
+ maxWidth: 400,
+ contentAsHTML: true,
+ interactive: true
+ });
+
+ $('.reaction-button').each(function() {
+ var btnId = $(this).attr('id');
+ $(this).click(function(e) {
+ e.preventDefault();
+ var tooltiptext = `
+ <div class="post-reactions-list">
+ %s
+ </div>
+ `;
+ $(this).tooltipster('content', tooltiptext);
+ $(this).tooltipster('show', function() {
+ twemoji.parse($('.tooltipster-content')[0]);
+ });
+ });
+ });
+
+
+ });
+
+ function reactComment(btnId ,r) {
+ var btn = $('#' + btnId);
+ var reacts_list = btn.closest('.post-content').find('.reactions');
+ $.ajax({
+ type: 'post',
+ url: btn.data('commentlink') + 'post_reaction',
+ data: {
+ 'r' : r,
+ '_session_id' : $.cookie('_session_id')
+ },
+ success: function(res) {
+ var react_html = '';
+
+ for (var i in res.counts) {
+ react_html += '<span>' + res.emoji_unicode[i] + '</span> ' + res.counts[i];
+ }
+
+ reacts_list.html(react_html);
+ twemoji.parse(reacts_list[0]);
+ btn.tooltipster('hide');
+ }
+ });
+ }
+ ''' % self.get_reaction_tooltip_content() )
class PostThread(ew_core.Widget):
http://git-wip-us.apache.org/repos/asf/allura/blob/8d3b43b1/Allura/allura/model/artifact.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/artifact.py b/Allura/allura/model/artifact.py
index 21aad0d..74480f5 100644
--- a/Allura/allura/model/artifact.py
+++ b/Allura/allura/model/artifact.py
@@ -1055,22 +1055,11 @@ class ReactableArtifact(MappedClass):
"""Reaction support for the Artifact. Use as a mixin."""
- class __mongometa__:
- session = main_orm_session
- name = 'reaction'
-
- react_thumbs_up = FieldProperty(int, if_missing=0)
- react_thumbs_down = FieldProperty(int, if_missing=0)
- react_laugh = FieldProperty(int, if_missing=0)
- react_hooray = FieldProperty(int, if_missing=0)
- react_confused = FieldProperty(int, if_missing=0)
- react_heart = FieldProperty(int, if_missing=0)
-
+ react_counts = FieldProperty({str: None}, if_missing=dict())
+ # dict to store reaction counts
react_users = FieldProperty({str: None}, if_missing=dict())
# dict to store reactions vs usernames
- reaction_list = ['thumbs_up', 'thumbs_down', 'laugh', 'hooray', 'confused', 'heart']
-
def post_reaction(self, r, user):
current_reaction = self.user_reacted(user)
if current_reaction is None:
@@ -1079,11 +1068,13 @@ class ReactableArtifact(MappedClass):
self.react_users[r].append(user.username)
else:
self.react_users[r] = [user.username]
- self.update_react_count(r, 1)
+ self.update_react_count(r)
elif current_reaction == r:
# prev=current so remove
self.react_users[r].remove(user.username)
- self.update_react_count(r, -1)
+ self.update_react_count(r, add=False)
+ if len(self.react_users[r]) == 0:
+ self.react_users.pop(r)
else:
# prev!=currnet so remove prev then append
self.react_users[current_reaction].remove(user.username)
@@ -1091,29 +1082,27 @@ class ReactableArtifact(MappedClass):
self.react_users[r].append(user.username)
else:
self.react_users[r] = [user.username]
- self.update_react_count(current_reaction, -1)
- self.update_react_count(r, 1)
+ self.update_react_count(current_reaction, add=False)
+ self.update_react_count(r)
+ if len(self.react_users[current_reaction]) == 0:
+ self.react_users.pop(current_reaction)
def user_reacted(self, user):
- for i in self.reaction_list:
- if i in self.react_users:
- if user.username in self.react_users[i]:
- return i
+ for i in self.react_users:
+ if user.username in self.react_users[i]:
+ return i
return
- def update_react_count(self, r, i):
- if r == 'thumbs_up':
- self.react_thumbs_up += i
- elif r == 'thumbs_down':
- self.react_thumbs_down += i
- elif r == 'laugh':
- self.react_laugh += i
- elif r == 'hooray':
- self.react_hooray += i
- elif r == 'confused':
- self.react_confused += i
- elif r == 'heart':
- self.react_heart += i
+ def update_react_count(self, r, add=True):
+ i = 1
+ if not add:
+ i = -1
+ if r in self.react_counts:
+ self.react_counts[r] += i
+ if self.react_counts[r] == 0:
+ self.react_counts.pop(r)
+ else:
+ self.react_counts[r] = 1
class MovedArtifact(Artifact):
http://git-wip-us.apache.org/repos/asf/allura/blob/8d3b43b1/Allura/allura/public/nf/js/allura-base.js
----------------------------------------------------------------------
diff --git a/Allura/allura/public/nf/js/allura-base.js b/Allura/allura/public/nf/js/allura-base.js
index 87b414f..b59fbe2 100644
--- a/Allura/allura/public/nf/js/allura-base.js
+++ b/Allura/allura/public/nf/js/allura-base.js
@@ -254,72 +254,3 @@ $(function(){
});
});
});
-
-// Reaction support
-$(function(){
-
- $('.reaction-button').tooltipster({
- animation: 'fade',
- delay: 200,
- theme: 'tooltipster-default',
- trigger: 'click',
- position: 'top',
- iconCloning: false,
- maxWidth: 400,
- contentAsHTML: true,
- interactive: true
- });
-
- $('.reaction-button').each(function() {
- var btnId = $(this).attr('id');
- $(this).click(function(e) {
- e.preventDefault();
- var tooltiptext = `
- <div class="post-reactions-list">
- <span onclick="reactComment('` + btnId + `', 'thumbs_up')"><img draggable="false" class="emoji" alt="👍" src="https://twemoji.maxcdn.com/2/72x72/1f44d.png"></span>
- <span onclick="reactComment('` + btnId + `', 'thumbs_down')"><img draggable="false" class="emoji" alt="👎" src="https://twemoji.maxcdn.com/2/72x72/1f44e.png"></span>
- <span onclick="reactComment('` + btnId + `', 'laugh')"><img draggable="false" class="emoji" alt="😃" src="https://twemoji.maxcdn.com/2/72x72/1f603.png"></span>
- <span onclick="reactComment('` + btnId + `', 'hooray')"><img draggable="false" class="emoji" alt="🎉" src="https://twemoji.maxcdn.com/2/72x72/1f389.png"></span>
- <span onclick="reactComment('` + btnId + `', 'confused')"><img draggable="false" class="emoji" alt="😕" src="https://twemoji.maxcdn.com/2/72x72/1f615.png"></span>
- <span onclick="reactComment('` + btnId + `', 'heart')"><img draggable="false" class="emoji" alt="❤" src="https://twemoji.maxcdn.com/2/72x72/2764.png"></span>
- </div>
- `;
- $(this).tooltipster('content', tooltiptext);
- $(this).tooltipster('show');
- });
- });
-
-
-});
-
-function reactComment(btnId ,r) {
- var btn = $('#' + btnId);
- var reacts_list = btn.closest('.post-content').find('.reactions');
- $.ajax({
- type: 'post',
- url: btn.data('commentlink') + 'post_reaction',
- data: {
- 'r' : r,
- '_session_id' : $.cookie('_session_id')
- },
- success: function(res) {
- var react_html = '';
- if(res.react_thumbs_up > 0)
- react_html += '<span>👍</span> ' + res.react_thumbs_up;
- if(res.react_thumbs_down > 0)
- react_html += '<span>👎</span> ' + res.react_thumbs_down;
- if(res.react_laugh > 0)
- react_html += '<span>😄</span> ' + res.react_laugh;
- if(res.react_hooray > 0)
- react_html += '<span>🎉</span> ' + res.react_hooray;
- if(res.react_confused > 0)
- react_html += '<span>😕</span> ' + res.react_confused;
- if(res.react_heart > 0)
- react_html += '<span>❤</span> ' + res.react_heart;
-
- reacts_list.html(react_html);
- twemoji.parse(reacts_list[0]);
- btn.tooltipster('hide');
- }
- });
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/allura/blob/8d3b43b1/Allura/allura/templates/widgets/post_widget.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/widgets/post_widget.html b/Allura/allura/templates/widgets/post_widget.html
index 496d973..fc3f555 100644
--- a/Allura/allura/templates/widgets/post_widget.html
+++ b/Allura/allura/templates/widgets/post_widget.html
@@ -84,24 +84,9 @@
<div{% if h.has_access(value, 'moderate') %} class="active-md" data-markdownlink="{{value.url()}}" {% endif %}>{{g.markdown.cached_convert(value, 'text')|safe}}</div>
<div class='reactions' style='user-select: none; cursor: default'>
- {% if value.react_thumbs_up > 0 %}
- <span>{{ '\U0001F44D' }}</span> {{ value.react_thumbs_up }}
- {% endif %}
- {% if value.react_thumbs_down > 0 %}
- <span>{{ '\U0001F44E' }}</span> {{ value.react_thumbs_down }}
- {% endif %}
- {% if value.react_laugh > 0 %}
- <span>{{ '\U0001F604' }}</span> {{ value.react_laugh }}
- {% endif %}
- {% if value.react_hooray > 0 %}
- <span>{{ '\U0001F389' }}</span> {{ value.react_hooray }}
- {% endif %}
- {% if value.react_confused > 0 %}
- <span>{{ '\U0001F615' }}</span> {{ value.react_confused }}
- {% endif %}
- {% if value.react_heart > 0 %}
- <span>{{ '\U00002764' }}</span> {{ value.react_heart }}
- {% endif %}
+ {% for reaction in value.react_counts %}
+ <span>{{ g.emojize(reaction) }}</span> {{ value.react_counts[reaction] }}
+ {% endfor %}
</div>
{{lib.related_artifacts(value)}}
{% if value.edit_count %}
http://git-wip-us.apache.org/repos/asf/allura/blob/8d3b43b1/Allura/allura/tests/functional/test_discuss.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_discuss.py b/Allura/allura/tests/functional/test_discuss.py
index 5539710..15ef794 100644
--- a/Allura/allura/tests/functional/test_discuss.py
+++ b/Allura/allura/tests/functional/test_discuss.py
@@ -224,18 +224,20 @@ class TestDiscuss(TestDiscussBase):
response = self.app.post(
react_link,
params={
- 'r': 'heart'})
- assert response.json['status'] == 'ok' and response.json['react_heart'] == 1
+ 'r': ':+1:'})
+ assert response.json['status'] == 'ok' and response.json['counts'][':+1:'] == 1 and \
+ response.json['emoji_unicode'][':+1:'] == u'\U0001F44D'
response = self.app.post(
react_link,
params={
'r': 'invalid'})
- assert response.json['status'] == 'error' and response.json['react_heart'] == 1
+ assert response.json['status'] == 'error' and response.json['counts'][':+1:'] == 1 and \
+ response.json['emoji_unicode'][':+1:'] == u'\U0001F44D'
# anon users can't react comments
response = self.app.post(
react_link,
params={
- 'r': 'heart'},
+ 'r': ':+1:'},
extra_environ=dict(username='*anonymous'))
assert response.json['error'] == 'no_permission'
# even anon can't send invalid reactions
@@ -254,14 +256,16 @@ class TestDiscuss(TestDiscussBase):
response = self.app.post(
react_link,
params={
- 'r': 'thumbs_down'})
- assert response.json['status'] == 'ok' and response.json['react_thumbs_down'] == 1
+ 'r': ':-1:'})
+ assert response.json['status'] == 'ok' and response.json['counts'][':-1:'] == 1 and \
+ response.json['emoji_unicode'][':-1:'] == u'\U0001F44E'
response = self.app.post(
react_link,
params={
- 'r': 'thumbs_up'})
- assert response.json['status'] == 'ok' and response.json['react_thumbs_up'] == 1
- assert response.json['status'] == 'ok' and response.json['react_thumbs_down'] == 0
+ 'r': ':+1:'})
+ assert response.json['status'] == 'ok' and response.json['counts'][':+1:'] == 1 and \
+ ':-1:' not in response.json['counts'] and ':-1:' not in response.json['emoji_unicode'] and \
+ response.json['emoji_unicode'][':+1:'] == u'\U0001F44D'
def test_comment_post_reaction_undo(self):
r = self._make_post('This is a post')
@@ -271,13 +275,15 @@ class TestDiscuss(TestDiscussBase):
response = self.app.post(
react_link,
params={
- 'r': 'hooray'})
- assert response.json['status'] == 'ok' and response.json['react_hooray'] == 1
+ 'r': ':tada:'})
+ assert response.json['status'] == 'ok' and response.json['counts'][':tada:'] == 1 and \
+ response.json['emoji_unicode'][':tada:'] == u'\U0001F389'
response = self.app.post(
react_link,
params={
- 'r': 'hooray'})
- assert response.json['status'] == 'ok' and response.json['react_hooray'] == 0
+ 'r': ':tada:'})
+ assert response.json['status'] == 'ok' and ':tada:' not in response.json['counts'] and \
+ ':tada:' not in response.json['emoji_unicode']
def test_user_filter(self):
r = self._make_post('Test post')