Add social_enable_likes_messages conf setting - refs BT#15393

Allows to user add likes or dislikes to posts in social wall. Requires DB changes:

```sql
CREATE TABLE message_likes (id BIGINT AUTO_INCREMENT NOT NULL, message_id BIGINT NOT NULL, user_id INT NOT NULL, liked TINYINT(1) DEFAULT '0' NOT NULL, disliked TINYINT(1) DEFAULT '0' NOT NULL, updated_at DATETIME NOT NULL, INDEX IDX_B66CB196537A1329 (message_id), INDEX IDX_B66CB196A76ED395 (user_id), INDEX idx_message_likes_uid_mid (message_id, user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
ALTER TABLE message_likes ADD CONSTRAINT FK_B66CB196537A1329 FOREIGN KEY (message_id) REFERENCES message (id) ON DELETE CASCADE;
ALTER TABLE message_likes ADD CONSTRAINT FK_B66CB196A76ED395 FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE;
```

 - edit src/Chamilo/CoreBundle/Entity/MessageLikes.php
   and follow the instructions about the @ORM\Entity() line
 - edit src/Chamilo/CoreBundle/Entity/Message.php
   and fllow the instruccions about the @ORM\OneToMany line for the $likes property
 - launch composer install to rebuild the autoload.php
pull/2858/head
Angel Fernando Quiroz Campos 7 years ago
parent 2e92ad6327
commit 9af667f5af
  1. 98
      main/inc/ajax/social.ajax.php
  2. 84
      main/inc/lib/message.lib.php
  3. 49
      main/inc/lib/social.lib.php
  4. 12
      main/install/configuration.dist.php
  5. 1
      main/social/group_topics.php
  6. 61
      main/template/default/layout/main.js.tpl
  7. 17
      src/Chamilo/CoreBundle/Entity/Message.php
  8. 186
      src/Chamilo/CoreBundle/Entity/MessageLikes.php

@ -1,6 +1,9 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
use Chamilo\CoreBundle\Entity\Message;
use Chamilo\CoreBundle\Entity\MessageLikes;
use ChamiloSession as Session;
/**
@ -332,6 +335,101 @@ switch ($action) {
}
echo $html;
break;
case 'like_message':
header('Content-Type: application/json');
if (
api_is_anonymous() ||
!api_get_configuration_value('social_enable_likes_messages')
) {
echo json_encode(false);
exit;
}
$messageId = isset($_GET['id']) ? (int) $_GET['id'] : 0;
$status = isset($_GET['status']) ? $_GET['status'] : '';
$groupId = isset($_GET['group']) ? (int) $_GET['group'] : 0;
if (empty($messageId) || !in_array($status, ['like', 'dislike'])) {
echo json_encode(false);
exit;
}
$em = Database::getManager();
$messageRepo = $em->getRepository('ChamiloCoreBundle:Message');
$messageLikesRepo = $em->getRepository('ChamiloCoreBundle:MessageLikes');
/** @var Message $message */
$message = $messageRepo->find($messageId);
if (empty($message)) {
echo json_encode(false);
exit;
}
if ((int) $message->getGroupId() !== $groupId) {
echo json_encode(false);
exit;
}
if (!empty($message->getGroupId())) {
$usergroup = new UserGroup();
$groupInfo = $usergroup->get($groupId);
if (empty($groupInfo)) {
echo json_encode(false);
exit;
}
$isMember = $usergroup->is_group_member($groupId, $current_user_id);
if (GROUP_PERMISSION_CLOSED == $groupInfo['visibility'] && !$isMember) {
echo json_encode(false);
exit;
}
}
$user = api_get_user_entity($current_user_id);
$userLike = $messageLikesRepo->findOneBy(['message' => $message, 'user' => $user]);
if (empty($userLike)) {
$userLike = new MessageLikes();
$userLike
->setMessage($message)
->setUser($user);
}
if ('like' === $status) {
if ($userLike->isLiked()) {
echo json_encode(false);
exit;
}
$userLike
->setLiked(true)
->setDisliked(false);
} elseif ('dislike' === $status) {
if ($userLike->isDisliked()) {
echo json_encode(false);
exit;
}
$userLike
->setLiked(false)
->setDisliked(true);
}
$userLike
->setUpdatedAt(
api_get_utc_datetime(null, false, true)
);
$em->persist($userLike);
$em->flush();
echo json_encode(true);
break;
default:
echo '';
}

@ -1691,6 +1691,10 @@ class MessageManager
);
}
if (api_get_configuration_value('social_enable_likes_messages')) {
$links .= self::getLikesButton($main_message['id'], $current_user_id, $groupId);
}
$urlReply = $webCodePath.'social/message_for_group_form.inc.php?'
.http_build_query(
[
@ -1827,6 +1831,11 @@ class MessageManager
false
);
}
if (api_get_configuration_value('social_enable_likes_messages')) {
$links .= self::getLikesButton($topic['id'], $current_user_id, $groupId);
}
$links .= Display::toolbarButton(
$langReply,
$webCodePath.'social/message_for_group_form.inc.php?'
@ -2750,4 +2759,79 @@ class MessageManager
return $row['count'];
}
/**
* @param int $messageId
*
* @return array
*
* @throws \Doctrine\ORM\Query\QueryException
*/
public static function countLikesAndDislikes($messageId, $userId)
{
$em = Database::getManager();
$likesCount = $em
->createQuery('SELECT COUNT(l) FROM ChamiloCoreBundle:MessageLikes l
WHERE l.liked = true AND l.message = :message')
->setParameters(['message' => (int) $messageId])
->getSingleScalarResult();
$dislikesCount = $em
->createQuery('SELECT COUNT(l) FROM ChamiloCoreBundle:MessageLikes l
WHERE l.liked = false AND l.message = :message')
->setParameters(['message' => (int) $messageId])
->getSingleScalarResult();
$userLike = $em
->getRepository('ChamiloCoreBundle:MessageLikes')
->findOneBy(['message' => $messageId, 'user' => $userId]);
return [
'likes' => $likesCount,
'dislikes' => $dislikesCount,
'user_liked' => $userLike ? $userLike->isLiked() : false,
'user_disliked' => $userLike ? $userLike->isDisliked() : false,
];
}
/**
* @param int $messageId
* @param int $userId
* @param int $groupId Optional.
*
* @return string
* @throws \Doctrine\ORM\Query\QueryException
*/
public static function getLikesButton($messageId, $userId, $groupId = 0)
{
$countLikes = self::countLikesAndDislikes($messageId, $userId);
$btnLike = Display::button(
'like',
Display::returnFontAwesomeIcon('thumbs-up', '', true)
.PHP_EOL.'<span>'.$countLikes['likes'].'</span>',
[
'title' => get_lang('Like'),
'class' => 'btn btn-default social-like '.($countLikes['user_liked'] ? 'disabled' : ''),
'data-status' => 'like',
'data-message' => $messageId,
'data-group' => $groupId,
]
);
$btnDislike = Display::button(
'like',
Display::returnFontAwesomeIcon('thumbs-down', '', true)
.PHP_EOL.'<span>'.$countLikes['dislikes'].'</span>',
[
'title' => get_lang('Dislike'),
'class' => 'btn btn-default social-like '.($countLikes['user_disliked'] ? 'disabled' : ''),
'data-status' => 'dislike',
'data-message' => $messageId,
'data-group' => $groupId,
]
);
return $btnLike.PHP_EOL.$btnDislike;
}
}

@ -1801,7 +1801,7 @@ class SocialManager extends UserManager
) {
$messageId = $messageInfo['id'];
$messages = MessageManager::getMessagesByParent($messageInfo['id'], 0, $offset, $limit);
$formattedList = '<div class="sub-mediapost">';
$formattedList = '<div class="sub-mediapost row">';
$users = [];
// The messages are ordered by date descendant, for comments we need ascendant
@ -1857,16 +1857,16 @@ class SocialManager extends UserManager
$isAdmin = self::is_admin($users[$userIdLoop]['id']);
if ($userStatus === 5) {
if ($users[$userIdLoop]['has_certificates']) {
$iconStatus = '<img class="pull-left" src="'.$urlImg.'icons/svg/identifier_graduated.svg" width="22px" height="22px">';
$iconStatus = '<img src="'.$urlImg.'icons/svg/identifier_graduated.svg" width="22px" height="22px">';
} else {
$iconStatus = '<img class="pull-left" src="'.$urlImg.'icons/svg/identifier_student.svg" width="22px" height="22px">';
$iconStatus = '<img src="'.$urlImg.'icons/svg/identifier_student.svg" width="22px" height="22px">';
}
} else {
if ($userStatus === 1) {
if ($isAdmin) {
$iconStatus = '<img class="pull-left" src="'.$urlImg.'icons/svg/identifier_admin.svg" width="22px" height="22px">';
$iconStatus = '<img src="'.$urlImg.'icons/svg/identifier_admin.svg" width="22px" height="22px">';
} else {
$iconStatus = '<img class="pull-left" src="'.$urlImg.'icons/svg/identifier_teacher.svg" width="22px" height="22px">';
$iconStatus = '<img src="'.$urlImg.'icons/svg/identifier_teacher.svg" width="22px" height="22px">';
}
}
}
@ -1884,7 +1884,7 @@ class SocialManager extends UserManager
</a>';
$comment .= '</div>';
$comment .= '</div>';
$comment .= '<div class="col-md-9 col-xs-9 social-post-answers">';
$comment .= '<div class="col-md-7 col-xs-7 social-post-answers">';
$comment .= '<div class="user-data">';
$comment .= $iconStatus;
$comment .= '<div class="username"><a href="'.$url.'">'.$nameComplete.'</a>
@ -1895,23 +1895,31 @@ class SocialManager extends UserManager
$comment .= '</div>';
$comment .= '</div>';
$comment .= '<div class="col-md-3 col-xs-3 social-post-answers">';
$comment .= '<div class="pull-right btn-group btn-group-sm">';
$comment .= MessageManager::getLikesButton(
$message['id'],
$currentUserId
);
$isOwnWall = $currentUserId == $userIdLoop || $currentUserId == $receiverId;
if ($isOwnWall) {
$comment .= '<div class="col-md-1 col-xs-1 social-post-answers">';
$comment .= '<div class="pull-right deleted-mgs">';
$comment .= Display::url(
Display::returnFontAwesomeIcon('trash'),
Display::returnFontAwesomeIcon('trash', '', true),
'javascript:void(0)',
[
'id' => 'message_'.$message['id'],
'title' => get_lang('SocialMessageDelete'),
'onclick' => 'deleteComment('.$message['id'].')',
'class' => 'btn btn-default',
]
);
$comment .= '</div>';
$comment .= '</div>';
);
}
$comment .= '</div>';
$comment .= '</div>';
$comment .= '</div>';
return $comment;
}
@ -3123,20 +3131,29 @@ class SocialManager extends UserManager
$html = '';
$html .= '<div class="top-mediapost" >';
$html .= '<div class="pull-right btn-group btn-group-sm">';
$html .= MessageManager::getLikesButton(
$message['id'],
$currentUserId,
!empty($message['group_info']['id']) ? (int) $message['group_info']['id'] : 0
);
if ($canEdit) {
$htmlDelete = Display::url(
Display::returnFontAwesomeIcon('trash'),
Display::returnFontAwesomeIcon('trash', '', true),
'javascript:void(0)',
[
'id' => 'message_'.$message['id'],
'title' => get_lang('SocialMessageDelete'),
'onclick' => 'deleteMessage('.$message['id'].')',
'class' => 'btn btn-default',
]
);
$html .= '<div class="pull-right deleted-mgs">';
$html .= $htmlDelete;
$html .= '</div>';
}
$html .= '</div>';
$html .= '<div class="user-image" >';
$html .= '<a href="'.$urlAuthor.'">
@ -3151,7 +3168,7 @@ class SocialManager extends UserManager
$html .= '<div class="post-attachment" >';
$html .= $postAttachment;
$html .= '</div>';
$html .= '<p>'.Security::remove_XSS($message['content']).'</p>';
$html .= '<div>'.Security::remove_XSS($message['content']).'</div>';
$html .= '</div>';
$html .= '</div>'; // end mediaPost

@ -1144,6 +1144,18 @@ VALUES (2, 13, 'session_courses_read_only_mode', 'Lock Course In Session', 1, 1,
// Avoid add a reply-to header when a no-reply address is set.
//$_configuration['mail_no_reply_avoid_reply_to'] = false;
// Allows to user add likes or dislikes to posts in social wall. Requires DB changes:
// CREATE TABLE message_likes (id BIGINT AUTO_INCREMENT NOT NULL, message_id BIGINT NOT NULL, user_id INT NOT NULL, liked TINYINT(1) DEFAULT '0' NOT NULL, disliked TINYINT(1) DEFAULT '0' NOT NULL, updated_at DATETIME NOT NULL, INDEX IDX_B66CB196537A1329 (message_id), INDEX IDX_B66CB196A76ED395 (user_id), INDEX idx_message_likes_uid_mid (message_id, user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
// ALTER TABLE message_likes ADD CONSTRAINT FK_B66CB196537A1329 FOREIGN KEY (message_id) REFERENCES message (id) ON DELETE CASCADE;
// ALTER TABLE message_likes ADD CONSTRAINT FK_B66CB196A76ED395 FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE;
// In 1.11.8, before enabling this feature, you also need to:
// - edit src/Chamilo/CoreBundle/Entity/MessageLikes.php
// and follow the instructions about the @ORM\Entity() line
// - edit src/Chamilo/CoreBundle/Entity/Message.php
// and fllow the instruccions about the @ORM\OneToMany line for the $likes property
// - launch composer install to rebuild the autoload.php
//$_configuration['social_enable_likes_messages'] = false;
// KEEP THIS AT THE END
// -------- Custom DB changes
// Add user activation by confirmation email

@ -207,6 +207,5 @@ $tpl->assign('social_menu_block', $social_menu_block);
$tpl->assign('social_friend_block', $friend_html);
$tpl->assign('group_message', $group_message);
$tpl->assign('social_right_content', $social_right_content);
$tpl->assign('content', $content);
$social_layout = $tpl->get_template('social/groups_topics.tpl');
$tpl->display($social_layout);

@ -322,9 +322,64 @@ $(function() {
$("#notifications").load(_p.web_ajax + "online.ajax.php?a=get_users_online");
$(document).ready(function () {
$('video:not(.skip)').attr('preload', 'metadata');
})
$('video:not(.skip)').attr('preload', 'metadata');
function socialLikes() {
{% if 'social_enable_likes_messages'|api_get_configuration_value %}
$('body').on('click', '.social-like', function (e) {
e.preventDefault();
var $self = $(this),
status = $self.data('status') || '',
group = $self.data('group') || 0,
message = $self.data('message') || 0;
$
.getJSON(
'{{ _p.web_ajax }}social.ajax.php',
{'a': 'like_message', 'group': group, 'id': message, 'status': status}
)
.then(function (response) {
if (!response) {
return;
}
var $count = $self.children('span'),
currentCount = parseInt($count.text()) || 0;
if ('like' === status) {
var $dislike = $self.next(),
$dislikeCount = $dislike.children('span'),
dislikeCount = parseInt($dislikeCount.text()) || 0;
$count.text(++currentCount);
if ($dislike.prop('disabled') || $dislike.is('.disabled')) {
$dislikeCount.text(dislikeCount <= 0 ? 0 : --dislikeCount);
$dislike.removeClass('disabled').prop('disabled', false);
}
$self.addClass('disabled').prop('disabled', true);
} else if ('dislike' === status) {
var $like = $self.prev(),
$likeCount = $like.children('span'),
likeCount = parseInt($likeCount.text()) || 0;
$count.text(++currentCount);
if ($like.prop('disabled') || $like.is('.disabled')) {
$likeCount.text(likeCount <= 0 ? 0 : --likeCount);
$like.removeClass('disabled').prop('disabled', false);
}
$self.addClass('disabled').prop('disabled', true);
}
});
});
{% endif %}
}
socialLikes();
});
$(window).resize(function() {

@ -3,6 +3,7 @@
namespace Chamilo\CoreBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
@ -99,6 +100,22 @@ class Message
*/
protected $votes;
/**
* @var ArrayCollection
*
* Add @ to the next line if api_get_configuration_value('social_enable_likes_messages') is true
* ORM\OneToMany(targetEntity="Chamilo\CoreBundle\Entity\MessageLikes", mappedBy="message", orphanRemoval=true)
*/
protected $likes;
/**
* Message constructor.
*/
public function __construct()
{
$this->likes = new ArrayCollection();
}
/**
* Set userSenderId.
*

@ -0,0 +1,186 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Entity;
use Chamilo\UserBundle\Entity\User;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\Index;
/**
* Class MessageLikes.
*
* @package Chamilo\CoreBundle\Entity
*
* @ORM\Table(
* name="message_likes",
* indexes={
* @Index(name="idx_message_likes_uid_mid", columns={"message_id", "user_id"})
* }
* )
* Add @ to the next line if api_get_configuration_value('social_enable_likes_messages') is true
* ORM\Entity()
*/
class MessageLikes
{
/**
* @var int
*
* @ORM\Column(name="id", type="bigint")
* @ORM\Id()
* @ORM\GeneratedValue()
*/
private $id;
/**
* @var Message
*
* @ORM\ManyToOne(targetEntity="Chamilo\CoreBundle\Entity\Message", inversedBy="likes")
* @ORM\JoinColumn(name="message_id", referencedColumnName="id", nullable=false, onDelete="CASCADE")
*/
private $message;
/**
* @var User
*
* @ORM\ManyToOne(targetEntity="Chamilo\UserBundle\Entity\User")
* @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false, onDelete="CASCADE")
*/
private $user;
/**
* @var bool
*
* @ORM\Column(name="liked", type="boolean", options={"default": false})
*/
private $liked;
/**
* @var bool
*
* @ORM\Column(name="disliked", type="boolean", options={"default": false})
*/
private $disliked;
/**
* @var \DateTime
*
* @ORM\Column(name="updated_at", type="datetime", nullable=false)
*/
private $updatedAt;
/**
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* @param int $id
*
* @return MessageLikes
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* @return Message
*/
public function getMessage()
{
return $this->message;
}
/**
* @param Message $message
*
* @return MessageLikes
*/
public function setMessage(Message $message)
{
$this->message = $message;
return $this;
}
/**
* @return User
*/
public function getUser()
{
return $this->user;
}
/**
* @param User $user
*
* @return MessageLikes
*/
public function setUser(User $user)
{
$this->user = $user;
return $this;
}
/**
* @return bool
*/
public function isLiked()
{
return $this->liked;
}
/**
* @param bool $liked
*
* @return MessageLikes
*/
public function setLiked($liked)
{
$this->liked = $liked;
return $this;
}
/**
* @return bool
*/
public function isDisliked()
{
return $this->disliked;
}
/**
* @param bool $disliked
*
* @return MessageLikes
*/
public function setDisliked($disliked)
{
$this->disliked = $disliked;
return $this;
}
/**
* @return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* @param \DateTime $updatedAt
*
* @return MessageLikes
*/
public function setUpdatedAt(\DateTime $updatedAt)
{
$this->updatedAt = $updatedAt;
return $this;
}
}
Loading…
Cancel
Save