From 0c3b2df65b5ca931880a3b61e60ea11fbf555a6f Mon Sep 17 00:00:00 2001
From: ababi <albert.babi@savoirfairelinux.com>
Date: Mon, 9 Nov 2020 20:45:41 +0100
Subject: [PATCH] conference: host can add or remove moderator for a conference
 or rendez-vous

Change-Id: I89d3ef02fea54448f3b7bc38da5550cc52d6cbcd
---
 src/calladapter.cpp                           | 54 +++++++++++++++++++
 src/calladapter.h                             |  5 +-
 .../components/ParticipantContextMenu.qml     | 16 ++++++
 .../components/ParticipantOverlay.qml         |  5 ++
 4 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/src/calladapter.cpp b/src/calladapter.cpp
index ed1f2405c..23854a758 100644
--- a/src/calladapter.cpp
+++ b/src/calladapter.cpp
@@ -264,6 +264,7 @@ CallAdapter::getConferencesInfos()
                 data["y"] = participant["y"].toInt();
                 data["w"] = participant["w"].toInt();
                 data["h"] = participant["h"].toInt();
+                data["uri"] = participant["uri"];
                 data["active"] = participant["active"] == "true";
                 auto bestName = participant["uri"];
                 auto& accInfo = LRCInstance::accountModel().getAccountInfo(accountId_);
@@ -622,6 +623,44 @@ CallAdapter::isCurrentHost() const
     return true;
 }
 
+bool
+CallAdapter::participantIsHost(const QString& uri) const
+{
+    auto* convModel = LRCInstance::getCurrentConversationModel();
+    const auto convInfo = convModel->getConversationForUID(convUid_);
+    if (!convInfo.uid.isEmpty()) {
+        auto& accInfo = LRCInstance::getAccountInfo(accountId_);
+        auto* callModel = accInfo.callModel.get();
+        try {
+            auto call = callModel->getCall(convInfo.callId);
+            if (call.participantsInfos.size() == 0) {
+                return (uri.isEmpty() || uri == accInfo.profileInfo.uri);
+            } else {
+                return !convInfo.confId.isEmpty()
+                        && callModel->hasCall(convInfo.confId)
+                        && (uri.isEmpty() || uri == accInfo.profileInfo.uri);
+            }
+        } catch (...) {
+        }
+    }
+    return true;
+}
+
+bool
+CallAdapter::isModerator(const QString& uri) const
+{
+    auto* callModel = LRCInstance::getAccountInfo(accountId_).callModel.get();
+    auto* convModel = LRCInstance::getCurrentConversationModel();
+    const auto conversation = convModel->getConversationForUID(LRCInstance::getCurrentConvUid());
+    auto confId = conversation.confId;
+    if (confId.isEmpty())
+        confId = conversation.callId;
+    try {
+        return callModel->isModerator(confId, uri);
+    } catch (...) {}
+    return false;
+}
+
 bool
 CallAdapter::isCurrentModerator() const
 {
@@ -647,6 +686,21 @@ CallAdapter::isCurrentModerator() const
     return true;
 }
 
+void
+CallAdapter::setModerator(const QString& uri, const bool state)
+{
+    auto* callModel = LRCInstance::getAccountInfo(accountId_).callModel.get();
+    auto* convModel = LRCInstance::getCurrentConversationModel();
+    const auto conversation = convModel->getConversationForUID(LRCInstance::getCurrentConvUid());
+    auto confId = conversation.confId;
+    if (confId.isEmpty())
+        confId = conversation.callId;
+    try {
+        callModel->setModerator(confId, uri, state);
+    } catch (...) {}
+}
+
+
 int
 CallAdapter::getCurrentLayoutType() const
 {
diff --git a/src/calladapter.h b/src/calladapter.h
index a6b2978bd..a2a0da421 100644
--- a/src/calladapter.h
+++ b/src/calladapter.h
@@ -56,8 +56,11 @@ public:
     Q_INVOKABLE void maximizeParticipant(const QString& uri, bool isActive);
     Q_INVOKABLE void minimizeParticipant();
     Q_INVOKABLE void hangUpThisCall();
-    Q_INVOKABLE bool isCurrentModerator() const;
+    Q_INVOKABLE void setModerator(const QString& uri, const bool state);
     Q_INVOKABLE bool isCurrentHost() const;
+    Q_INVOKABLE bool participantIsHost(const QString& uri = {}) const;
+    Q_INVOKABLE bool isModerator(const QString& uri = {}) const;
+    Q_INVOKABLE bool isCurrentModerator() const;
     Q_INVOKABLE int getCurrentLayoutType() const;
     Q_INVOKABLE void holdThisCallToggle();
     Q_INVOKABLE void muteThisCallToggle();
diff --git a/src/mainview/components/ParticipantContextMenu.qml b/src/mainview/components/ParticipantContextMenu.qml
index 637a038dc..e508dabf9 100644
--- a/src/mainview/components/ParticipantContextMenu.qml
+++ b/src/mainview/components/ParticipantContextMenu.qml
@@ -35,6 +35,8 @@ Item {
     property var showHangup: false
     property var showMaximize: false
     property var showMinimize: false
+    property var showSetModerator: false
+    property var showUnsetModerator: false
 
     function openMenu(){
         ContextMenuGenerator.initMenu()
@@ -58,6 +60,20 @@ Item {
                                                   CallAdapter.minimizeParticipant()
                                              })
 
+        if (showSetModerator)
+            ContextMenuGenerator.addMenuItem(qsTr("Set moderator"),
+                                             "qrc:/images/icons/person_add-24px.svg",
+                                             function (){
+                                                  CallAdapter.setModerator(uri, true)
+                                             })
+
+        if (showUnsetModerator)
+            ContextMenuGenerator.addMenuItem(qsTr("Unset moderator"),
+                                             "qrc:/images/icons/round-close-24px.svg",
+                                             function (){
+                                                  CallAdapter.setModerator(uri, false)
+                                             })
+
         root.height = ContextMenuGenerator.getMenu().height
         root.width = ContextMenuGenerator.getMenu().width
         ContextMenuGenerator.getMenu().open()
diff --git a/src/mainview/components/ParticipantOverlay.qml b/src/mainview/components/ParticipantOverlay.qml
index 530a61ba6..fc3cb6d8a 100644
--- a/src/mainview/components/ParticipantOverlay.qml
+++ b/src/mainview/components/ParticipantOverlay.qml
@@ -155,6 +155,9 @@ Rectangle {
                         var layout = CallAdapter.getCurrentLayoutType()
                         var showMaximized = layout !== 2
                         var showMinimized = !(layout === 0 || (layout === 1 && !active))
+                        var isModerator = CallAdapter.isModerator(uri)
+                        var isHost = CallAdapter.isCurrentHost()
+                        var participantIsHost = CallAdapter.participantIsHost(uri)
                         injectedContextMenu.showHangup = !root.isLocal && showEndCall
                         injectedContextMenu.showMaximize = showMaximized
                         injectedContextMenu.showMinimize = showMinimized
@@ -162,6 +165,8 @@ Rectangle {
                         injectedContextMenu.active = active
                         injectedContextMenu.x = mousePos.x
                         injectedContextMenu.y = mousePos.y - injectedContextMenu.height
+                        injectedContextMenu.showSetModerator = (isHost && !participantIsHost && !isModerator)
+                        injectedContextMenu.showUnsetModerator = (isHost && !participantIsHost && isModerator)
                         injectedContextMenu.openMenu()
                     }
                 }
-- 
GitLab