Added participant ban feature (#879)

Co-authored-by: Patrick Schmidt (Clon1998)
This commit is contained in:
Alex Andres 2024-02-08 20:32:06 +01:00 committed by GitHub
parent fea24d42ca
commit 87b432ddb2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 150 additions and 9 deletions

View file

@ -694,6 +694,10 @@ public class SlidesPresenter extends Presenter<SlidesView> {
view.removeSpeechRequest(message);
}
private void onBan(CourseParticipant user) {
streamService.ban(user);
}
private void onDiscardMessage(MessengerMessage message) {
PresenterContext presenterContext = (PresenterContext) context;
presenterContext.getMessengerMessages().remove(message);
@ -1368,6 +1372,7 @@ public class SlidesPresenter extends Presenter<SlidesView> {
view.setOnAcceptSpeech(this::onAcceptSpeech);
view.setOnRejectSpeech(this::onRejectSpeech);
view.setOnBan(this::onBan);
view.setOnDiscardMessage(this::onDiscardMessage);
view.setOnCreateMessageSlide(this::onCreateMessageSlide);
view.setOnMutePeerAudio(streamService::mutePeerAudio);

View file

@ -81,6 +81,7 @@ import org.lecturestudio.web.api.stream.StreamVideoContext;
import org.lecturestudio.web.api.stream.client.StreamWebSocketClient;
import org.lecturestudio.web.api.stream.StreamContext;
import org.lecturestudio.web.api.stream.model.Course;
import org.lecturestudio.web.api.stream.model.CourseParticipant;
import org.lecturestudio.web.api.stream.service.StreamProviderService;
import org.lecturestudio.web.api.websocket.WebSocketBearerTokenProvider;
import org.lecturestudio.web.api.websocket.WebSocketHeaderProvider;
@ -183,6 +184,16 @@ public class WebRtcStreamService extends ExecutableBase {
streamProviderService.rejectSpeechRequest(message.getRequestId());
}
public void ban(CourseParticipant user) {
if (!started()) {
return;
}
long courseId = streamContext.getCourse().getId();
streamProviderService.banParticipantFromCourse(courseId, user.getUserId());
}
public void startCameraStream() throws ExecutableException {
if (streamState != ExecutableState.Started || cameraState == ExecutableState.Started) {
return;

View file

@ -112,6 +112,8 @@ public interface SlidesView extends View {
void setOnAcceptSpeech(ConsumerAction<SpeechBaseMessage> action);
void setOnBan(ConsumerAction<CourseParticipant> action);
void setOnRejectSpeech(ConsumerAction<SpeechBaseMessage> action);
void setPeerStateEvent(PeerStateEvent event);

View file

@ -854,6 +854,11 @@ public class SwingSlidesView extends JPanel implements SlidesView {
participantList.setOnRejectSpeech(action);
}
@Override
public void setOnBan(ConsumerAction<CourseParticipant> action) {
participantList.setOnBan(action);
}
@Override
public void setPeerStateEvent(PeerStateEvent event) {
SwingUtils.invoke(() -> {

View file

@ -36,20 +36,14 @@ import java.util.ResourceBundle;
import java.util.TreeSet;
import javax.inject.Inject;
import javax.swing.AbstractListModel;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.ListSelectionModel;
import javax.swing.*;
import org.lecturestudio.core.beans.ObjectProperty;
import org.lecturestudio.core.view.ConsumerAction;
import org.lecturestudio.swing.list.ParticipantCellRenderer;
import org.lecturestudio.web.api.message.SpeechBaseMessage;
import org.lecturestudio.web.api.stream.model.CourseParticipant;
import org.lecturestudio.web.api.stream.model.CourseParticipantType;
import org.lecturestudio.web.api.stream.model.CoursePresenceType;
public class ParticipantList extends JPanel {
@ -58,6 +52,12 @@ public class ParticipantList extends JPanel {
private final Map<String, ConsumerAction<?>> actionMap;
private CourseParticipantItem popupMenuParticipant;
private final JPopupMenu popupMenu;
private final JMenuItem popupMenuBanItem;
@Inject
public ParticipantList(ResourceBundle bundle) {
@ -70,6 +70,20 @@ public class ParticipantList extends JPanel {
listModel = new SortedListModel();
actionMap = new HashMap<>();
popupMenuBanItem = new JMenuItem("Ban");
popupMenuBanItem.addActionListener(e -> {
if (nonNull(popupMenuParticipant)) {
var action = (ConsumerAction<CourseParticipant>) actionMap.get("ban-user");
if (action == null) {
return;
}
action.execute(popupMenuParticipant);
}
});
popupMenu = new JPopupMenu();
popupMenu.add(popupMenuBanItem);
JList<CourseParticipantItem> list = new JList<>(listModel) {
@Override
@ -144,6 +158,10 @@ public class ParticipantList extends JPanel {
actionMap.put("speech-reject", action);
}
public void setOnBan(ConsumerAction<CourseParticipant> action) {
actionMap.put("ban-user", action);
}
private class MouseHandler extends MouseAdapter {
@ -171,11 +189,33 @@ public class ParticipantList extends JPanel {
if (index == -1 && !e.isShiftDown() && !e.isControlDown()) {
list.clearSelection();
}
// Ensure the user is always reset
popupMenuParticipant = null;
if (index > -1) {
handleButton(e.getPoint(), index);
if (e.getButton() == MouseEvent.BUTTON3) {
handleRightClick(e, index);
}
else if (e.getButton() == MouseEvent.BUTTON1) {
handleButton(e.getPoint(), index);
}
}
}
private void handleRightClick(MouseEvent e, int index) {
CourseParticipantItem value = listModel.getElementAt(index);
if (value == null) {
return;
}
if (value.getParticipantType() != CourseParticipantType.PARTICIPANT) {
return;
}
popupMenuParticipant = value;
popupMenu.show(e.getComponent(), e.getX(), e.getY());
}
@SuppressWarnings("unchecked")
private void handleButton(Point pt, int index) {
CourseParticipantItem value = listModel.getElementAt(index);

View file

@ -0,0 +1,32 @@
/*
* Copyright (C) 2020 TU Darmstadt, Department of Computer Science,
* Embedded Systems and Applications Group.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.lecturestudio.web.api.message;
import lombok.Getter;
import lombok.Setter;
import org.lecturestudio.web.api.stream.model.ModerationType;
@Getter
@Setter
public final class CourseParticipantModerationEvent extends UserMessage {
ModerationType moderationType;
}

View file

@ -175,4 +175,14 @@ public interface StreamRestClient {
void updateStreamMediaState(@PathParam("courseId") long courseId,
Map<org.lecturestudio.core.net.MediaType, Boolean> state);
/**
* Ban a participant/user from a course.
*
* @param courseId The unique course ID.
* @param userId The user ID.
*/
@POST
@Path("/participant/{courseId}/ban/{userId}")
void banParticipantFromCourse(@PathParam("courseId") long courseId,
@PathParam("userId") String userId);
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (C) 2020 TU Darmstadt, Department of Computer Science,
* Embedded Systems and Applications Group.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.lecturestudio.web.api.stream.model;
/**
* Enumeration of moderation types.
*/
public enum ModerationType {
PERMANENT_BAN,
}

View file

@ -181,4 +181,13 @@ public class StreamProviderService extends ProviderService {
Map<MediaType, Boolean> state) {
streamRestClient.updateStreamMediaState(courseId, state);
}
/**
* Sends a message to the server in order to ban a user from a course.
*
* @param userId The user to ban.
*/
public void banParticipantFromCourse(long courseId, String userId) {
streamRestClient.banParticipantFromCourse(courseId, userId);
}
}