Merge branch 'master' of github.com:chamilo/chamilo-lms

pull/4161/head
Julio 3 years ago
commit 96b405135f
  1. 54
      assets/vue/components/socialnetwork/Post.vue
  2. 79
      assets/vue/components/socialnetwork/PostComment.vue
  3. 56
      assets/vue/components/socialnetwork/PostForm.vue
  4. 0
      assets/vue/components/socialnetwork/WallForm.vue
  5. 2
      assets/vue/views/socialnetwork/Wall.vue
  6. 15
      public/main/install/configuration.dist.php
  7. 29
      src/CoreBundle/Entity/Message.php
  8. 3
      src/CoreBundle/EventListener/TwigListener.php
  9. 13
      src/CoreBundle/Migrations/Schema/V200/Version20170627122900.php
  10. 6
      src/CoreBundle/Settings/SocialSettingsSchema.php

@ -12,7 +12,9 @@
</q-item-section>
<q-item-section>
<q-item-label v-if="message.sender['@id'] === message.firstReceiver.receiver['@id']">
<q-item-label
v-if="!message.firstReceiver || (message.firstReceiver && message.sender['@id'] === message.firstReceiver.receiver['@id'])"
>
<router-link :to="{ name: 'SocialNetworkWall', query: { id: message.sender['@id']} }">
{{ message.sender.username }}
</router-link>
@ -46,12 +48,36 @@
:src="attachment.contentUrl"
/>
<q-card-section v-html="message.content" />
<q-separator />
<q-list
v-if="comments.length"
>
<q-item-label header>{{ $t('Comments') }}</q-item-label>
<SocialNetworkPostComment
v-for="(comment, index) in comments"
:key="index"
:comment="comment"
@deleted="onDeletedComment(index)"
/>
</q-list>
<SocialNetworkPostForm :post="message" />
</q-card>
</template>
<script>
import SocialNetworkPostForm from "./PostForm";
import {onMounted, reactive} from "vue";
import SocialNetworkPostComment from "./PostComment";
import {MESSAGE_TYPE_WALL} from "../message/constants";
import {useStore} from "vuex";
export default {
name: "SocialNetworkPost",
components: {SocialNetworkPostComment, SocialNetworkPostForm},
props: {
message: {
type: Object,
@ -60,14 +86,38 @@ export default {
},
setup(props) {
const attachment = props.message.attachments.length ? props.message.attachments[0] : null;
let comments = reactive([]);
const containsImage = attachment && attachment.resourceNode.resourceFile.mimeType.includes('image/');
const containsVideo = attachment && attachment.resourceNode.resourceFile.mimeType.includes('video/');
function loadComments() {
const store = useStore();
store
.dispatch(
'message/findAll',
{
parent: props.message['@id'],
msgType: MESSAGE_TYPE_WALL,
'order[sendDate]': 'desc',
}
)
.then(response => comments.push(...response));
}
function onDeletedComment(index) {
comments.splice(index, 1);
}
onMounted(loadComments);
return {
attachment,
containsImage,
containsVideo
containsVideo,
comments,
onDeletedComment,
}
}
}

@ -0,0 +1,79 @@
<template>
<q-item bordered>
<q-item-section avatar top>
<q-avatar>
<img :src="comment.sender.illustrationUrl">
</q-avatar>
</q-item-section>
<q-item-section>
<q-item-label class="font-bold" lines="1">{{ comment.sender.username }}</q-item-label>
<q-item-label v-html="comment.content" />
<q-item-label caption>{{ $filters.relativeDatetime(comment.sendDate) }}</q-item-label>
</q-item-section>
<q-item-section side top>
<q-btn
v-if="enableMessagesFeedbackConfig"
:label="comment.countLikes"
:title="$t('Like')"
dense
flat
icon="mdi-heart-plus"
/>
<q-btn
v-if="enableMessagesFeedbackConfig && !disableDislikeOption"
:label="comment.countDislikes"
:title="$t('Dislike')"
dense
flat
icon="mdi-heart-remove"
/>
<q-btn
v-if="isOwner"
:title="$t('Delete comment')"
dense
flat
icon="delete"
@click="deleteComment"
/>
</q-item-section>
</q-item>
</template>
<script>
import {useStore} from "vuex";
import {ref} from "vue";
export default {
name: "SocialNetworkPostComment",
props: {
comment: {
type: Object,
required: true
}
},
emits: ['deleted'],
setup(props, context) {
const store = useStore();
const currentUser = store.getters['security/getUser'];
function deleteComment() {
store
.dispatch('message/del', props.comment)
.then(() => context.emit('deleted'));
}
const enableMessagesFeedbackConfig = ref(window.config['social.social_enable_messages_feedback'] === 'true');
const disableDislikeOption = ref(window.config['social.disable_dislike_option'] === 'true');
return {
deleteComment,
isOwner: currentUser['@id'] === props.comment.sender['@id'],
enableMessagesFeedbackConfig,
disableDislikeOption,
};
}
}
</script>

@ -0,0 +1,56 @@
<template>
<q-form class="q-gutter-md p-4 pt-0">
<q-input
v-model="comment"
:label="$t('Write new comment')"
autogrow
/>
<div class="row justify-end">
<q-btn
:label="$t('Post')"
icon="send"
@click="sendComment"
/>
</div>
</q-form>
</template>
<script>
import {ref} from "vue";
import {useStore} from "vuex";
import {MESSAGE_TYPE_WALL} from "../message/constants";
export default {
name: "SocialNetworkPostForm",
props: {
post: {
type: Object,
required: true,
}
},
setup(props) {
const store = useStore();
const currentUser = store.getters['security/getUser'];
const comment = ref('');
async function sendComment() {
await store.dispatch('message/create', {
title: 'Comment',
content: comment.value,
msgType: MESSAGE_TYPE_WALL,
sender: currentUser['@id'],
parent: props.post['@id'],
});
comment.value = '';
}
return {
sendComment,
comment
};
}
}
</script>

@ -7,7 +7,7 @@
</template>
<script>
import SocialNetworkForm from "../../components/socialnetwork/Form";
import SocialNetworkForm from "../../components/socialnetwork/WallForm";
import SocialNetworkPostList from "../../components/socialnetwork/PostList";
export default {

@ -1039,21 +1039,6 @@ $_configuration['required_extra_fields_in_profile'] = [
// 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 feedback (likes or dislikes) to posts in social wall. Requires DB changes:
// CREATE TABLE message_feedback (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_DB0F8049537A1329 (message_id), INDEX IDX_DB0F8049A76ED395 (user_id), INDEX idx_message_feedback_uid_mid (message_id, user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
// ALTER TABLE message_feedback ADD CONSTRAINT FK_DB0F8049537A1329 FOREIGN KEY (message_id) REFERENCES message (id) ON DELETE CASCADE;
// ALTER TABLE message_feedback ADD CONSTRAINT FK_DB0F8049A76ED395 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/MessageFeedback.php
// and follow the instructions about the @ORM\Entity() line
// - edit src/Chamilo/CoreBundle/Entity/Message.php
// and follow the instructions about the @ORM\OneToMany line for the $likes property
// - launch "composer install" to rebuild the autoload.php
//$_configuration['social_enable_messages_feedback'] = false;
// Disable dislike button in the social network.
//$_configuration['disable_dislike_option'] = false;
// Block student's access to the course documents when using the ckeditor "Browse server" button
//$_configuration['block_editor_file_manager_for_students'] = false;
// Show a language flag next to the user picture in the social network

@ -93,6 +93,7 @@ use Symfony\Component\Validator\Constraints as Assert;
'sender' => 'exact',
'receivers.receiver' => 'exact',
'receivers.tags.tag' => 'exact',
'parent' => 'exact',
])]
class Message
{
@ -216,6 +217,7 @@ class Message
* @ORM\ManyToOne(targetEntity="Message", inversedBy="children")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
*/
#[Groups(['message:write'])]
protected ?Message $parent = null;
/**
@ -238,12 +240,17 @@ class Message
protected Collection $attachments;
/**
* @var Collection|MessageFeedback[]
* @var Collection<int, MessageFeedback>
*
* @ORM\OneToMany(targetEntity="MessageFeedback", mappedBy="message", orphanRemoval=true)
*/
protected Collection $likes;
#[Groups(['message:read'])]
protected int $countLikes = 0;
#[Groups(['message:read'])]
protected int $countDislikes = 0;
public function __construct()
{
$this->sendDate = new DateTime('now');
@ -543,4 +550,24 @@ class Message
return $this;
}
public function getCountLikes(): int
{
$criteria = Criteria::create();
$criteria->where(
Criteria::expr()->eq('liked', true)
);
return $this->likes->matching($criteria)->count();
}
public function getCountDislikes(): int
{
$criteria = Criteria::create();
$criteria->where(
Criteria::expr()->eq('disliked', true)
);
return $this->likes->matching($criteria)->count();
}
}

@ -71,6 +71,9 @@ class TwigListener
'platform.load_term_conditions_section',
'registration.allow_terms_conditions',
'agenda.personal_calendar_show_sessions_occupation',
'social.social_enable_messages_feedback',
'social.disable_dislike_option',
];
// @todo get variables in 1 query.

@ -347,6 +347,19 @@ class Version20170627122900 extends AbstractMigrationChamilo
"INSERT INTO settings_current (access_url, variable, category, selected_value, title, access_url_changeable, access_url_locked) VALUES (1, 'ticket_project_user_roles', 'Ticket', '$selectedValue', 'ticket_project_user_roles', 1, 1)"
);
}
// social configurations
if ($this->getConfigurationValue('social_enable_messages_feedback')) {
$this->addSql(
"INSERT INTO settings_current (access_url, variable, category, selected_value, title, access_url_changeable, access_url_locked) VALUES (1, 'social_enable_messages_feedback', 'Social', 'true', 'social_enable_messages_feedback', 1, 1)"
);
}
if ($this->getConfigurationValue('disable_dislike_option')) {
$this->addSql(
"INSERT INTO settings_current (access_url, variable, category, selected_value, title, access_url_changeable, access_url_locked) VALUES (1, 'disable_dislike_option', 'Social', 'true', 'disable_dislike_option', 1, 1)"
);
}
}
public function down(Schema $schema): void

@ -19,12 +19,16 @@ class SocialSettingsSchema extends AbstractSettingsSchema
[
'allow_social_tool' => 'true',
'allow_students_to_create_groups_in_social' => 'false',
'social_enable_messages_feedback' => 'false',
'disable_dislike_option' => 'false',
]
)
;
$allowedTypes = [
'allow_social_tool' => ['string'],
'allow_students_to_create_groups_in_social' => ['string'],
'social_enable_messages_feedback' => ['string'],
'disable_dislike_option' => ['string'],
];
$this->setMultipleAllowedTypes($allowedTypes, $builder);
}
@ -34,6 +38,8 @@ class SocialSettingsSchema extends AbstractSettingsSchema
$builder
->add('allow_social_tool', YesNoType::class)
->add('allow_students_to_create_groups_in_social', YesNoType::class)
->add('social_enable_messages_feedback', YesNoType::class)
->add('disable_dislike_option', YesNoType::class)
;
}
}

Loading…
Cancel
Save