Skip to content

Commit

Permalink
Merge pull request #1078 from nextcloud/feature/noid/guest-moderators…
Browse files Browse the repository at this point in the history
…-prework

Allow to make guests moderators
  • Loading branch information
nickvergessen authored Oct 5, 2018
2 parents de5a314 + f39142c commit 546526a
Show file tree
Hide file tree
Showing 16 changed files with 492 additions and 124 deletions.
2 changes: 2 additions & 0 deletions docs/api-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,8 @@ Base endpoint is: `/ocs/v2.php/apps/spreed/api/v1`
* `user_removed` - {actor} removed {user} from the conversation
* `moderator_promoted` - {actor} promoted {user} to moderator
* `moderator_demoted` - {actor} demoted {user} from moderator
* `guest_moderator_promoted` - {actor} promoted {user} to moderator
* `guest_moderator_demoted` - {actor} demoted {user} from moderator

## Guests

Expand Down
28 changes: 26 additions & 2 deletions js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
USER: 3,
GUEST: 4,
USERSELFJOINED: 5,
GUEST_MODERATOR: 6,

/* Must stay in sync with values in "lib/Room.php". */
FLAG_DISCONNECTED: 0,
Expand Down Expand Up @@ -373,13 +374,15 @@
id: 'participantsTabView'
});

this.signaling.on('participantListChanged', function() {
this._participantsListChangedCallback = function() {
// The "participantListChanged" event can be triggered by the
// signaling before the room is set in the collection.
if (this._participants.url) {
this._participants.fetch();
}
}.bind(this));
}.bind(this);

this.signaling.on('participantListChanged', this._participantsListChangedCallback);

this._participantsView.listenTo(this._rooms, 'change:active', function(model, active) {
if (active) {
Expand All @@ -389,6 +392,15 @@

this._sidebarView.addTab('participants', { label: t('spreed', 'Participants'), icon: 'icon-contacts-dark' }, this._participantsView);
},
_hideParticipantList: function() {
this._sidebarView.removeTab('participants');

this.signaling.off('participantListChanged', this._participantsListChangedCallback);

delete this._participantsListChangedCallback;
delete this._participantsView;
delete this._participants;
},
/**
* @param {string} token
*/
Expand Down Expand Up @@ -666,6 +678,18 @@
// in the public share auth page).
this.activeRoom = new OCA.SpreedMe.Models.Room({ token: this.token });
this.signaling.setRoom(this.activeRoom);

this.listenTo(this.activeRoom, 'change:participantType', function(model, participantType) {
if (participantType === OCA.SpreedMe.app.GUEST_MODERATOR) {
this._showParticipantList();
// The public page supports only a single room, so the
// active room has to be explicitly set as it will not
// be set in a 'change:active' event.
this._participantsView.setRoom(this.activeRoom);
} else {
this._hideParticipantList();
}
});
}

this._registerPageEvents();
Expand Down
7 changes: 7 additions & 0 deletions js/views/callinfoview.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@
' </div>' +
'{{#if canModerate}}' +
' <div class="share-link-options">' +
' {{#if canFullModerate}}' +
' <input name="link-checkbox" id="link-checkbox" class="checkbox link-checkbox" value="1" {{#if isPublic}} checked="checked"{{/if}} type="checkbox">' +
' <label for="link-checkbox" class="link-checkbox-label">' + t('spreed', 'Share link') + '</label>' +
' {{/if}}' +
' {{#if isPublic}}' +
' <div class="clipboard-button"><span class="button icon-clippy"></span></div>' +
' <div class="password-button">' +
Expand Down Expand Up @@ -88,6 +90,7 @@
isGuest: this.model.get('participantType') === 4,
isInCall: (this.model.get('participantFlags') & OCA.SpreedMe.app.FLAG_IN_CALL) !== 0,
canModerate: canModerate,
canFullModerate: this._canFullModerate(),
isPublic: this.model.get('type') === 3,
showShareLink: !canModerate && this.model.get('type') === 3,
isDeletable: canModerate && (Object.keys(this.model.get('participants')).length > 2 || this.model.get('numGuests') > 0)
Expand Down Expand Up @@ -235,6 +238,10 @@
},

_canModerate: function() {
return this._canFullModerate() || this.model.get('participantType') === 6;
},

_canFullModerate: function() {
return this.model.get('participantType') === 1 || this.model.get('participantType') === 2;
},

Expand Down
85 changes: 64 additions & 21 deletions js/views/participantlistview.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
' {{name}}' +
'{{#if participantIsOwner}}<span class="participant-moderator-indicator">(' + t('spreed', 'moderator') + ')</span>{{/if}}' +
'{{#if participantIsModerator}}<span class="participant-moderator-indicator">(' + t('spreed', 'moderator') + ')</span>{{/if}}' +
'{{#if participantIsGuestModerator}}<span class="participant-moderator-indicator">(' + t('spreed', 'moderator') + ')</span>{{/if}}' +
'{{#if inCall}}<span class="icon icon-video"></span>{{/if}}' +
'</a>'+
'{{#if canModerate}}' +
Expand All @@ -48,15 +49,15 @@
'</div>'+
'<div class="popovermenu bubble menu">'+
'<ul class="popovermenu-list">'+
'{{#if participantIsModerator}}' +
'{{#if canBeDemoted}}' +
'<li>' +
'<button class="demote-moderator">' +
'<span class="icon icon-star"></span>' +
'<span>' + t('spreed', 'Demote from moderator') + '</span>' +
'</button>' +
'</li>' +
'{{else}}' +
'{{#if participantIsUser}}' +
'{{#if canBePromoted}}' +
'<li>' +
'<button class="promote-moderator">' +
'<span class="icon icon-rename"></span>' +
Expand Down Expand Up @@ -108,10 +109,19 @@
});
},
templateContext: function() {
var isSelf = false,
isModerator = false;
if (OC.getCurrentUser().uid) {
isSelf = this.model.get('userId') === OC.getCurrentUser().uid;
isModerator = OCA.SpreedMe.app.activeRoom.get('participantType') === OCA.SpreedMe.app.OWNER ||
OCA.SpreedMe.app.activeRoom.get('participantType') === OCA.SpreedMe.app.MODERATOR;
} else {
isSelf = this.model.get('sessionId') === OCA.SpreedMe.app.activeRoom.get('sessionId');
isModerator = OCA.SpreedMe.app.activeRoom.get('participantType') === OCA.SpreedMe.app.GUEST_MODERATOR;
}

var canModerate = this.model.get('participantType') !== OCA.SpreedMe.app.OWNER && // can not moderate owners
this.model.get('userId') !== OC.getCurrentUser().uid && // can not moderate yourself
(OCA.SpreedMe.app.activeRoom.get('participantType') === OCA.SpreedMe.app.OWNER || // current user must be owner
OCA.SpreedMe.app.activeRoom.get('participantType') === OCA.SpreedMe.app.MODERATOR), // or moderator.
!isSelf && isModerator,
name = '';


Expand All @@ -123,8 +133,11 @@

return {
canModerate: canModerate,
canBePromoted: this.model.get('participantType') === OCA.SpreedMe.app.USER || this.model.get('participantType') === OCA.SpreedMe.app.GUEST,
canBeDemoted: this.model.get('participantType') === OCA.SpreedMe.app.MODERATOR || this.model.get('participantType') === OCA.SpreedMe.app.GUEST_MODERATOR,
name: name,
participantIsUser: this.model.get('participantType') === OCA.SpreedMe.app.USER,
participantIsGuestModerator: this.model.get('participantType') === OCA.SpreedMe.app.GUEST_MODERATOR,
participantIsModerator: this.model.get('participantType') === OCA.SpreedMe.app.MODERATOR,
participantIsOwner: this.model.get('participantType') === OCA.SpreedMe.app.OWNER
};
Expand All @@ -134,11 +147,14 @@
this.$el.find('.avatar').each(function() {
var $element = $(this);

if (model.get('participantType') !== OCA.SpreedMe.app.GUEST) {
$element.avatar(model.get('userId'), 32, undefined, false, undefined, model.get('displayName'));
} else {
if (model.get('participantType') === OCA.SpreedMe.app.GUEST_MODERATOR) {
$element.imageplaceholder('M', model.get('displayName'), 32);
$element.css('background-color', '#b9b9b9');
} else if (model.get('participantType') === OCA.SpreedMe.app.GUEST) {
$element.imageplaceholder('?', model.get('displayName'), 32);
$element.css('background-color', '#b9b9b9');
} else {
$element.avatar(model.get('userId'), 32, undefined, false, undefined, model.get('displayName'));
}
});

Expand Down Expand Up @@ -181,25 +197,38 @@
this.toggleMenuClass();
},
promoteToModerator: function() {
if (this.model.get('participantType') !== OCA.SpreedMe.app.USER) {
if (this.model.get('participantType') !== OCA.SpreedMe.app.USER &&
this.model.get('participantType') !== OCA.SpreedMe.app.GUEST) {
return;
}

this.closeMenu();
this.ui.menuButton.addClass('hidden');
this.ui.menuButtonIconLoading.removeClass('hidden');

var participantId = this.model.get('userId'),
var data = {},
self = this;

if (this.model.get('userId')) {
data = {
participant: this.model.get('userId')
};
} else {
data = {
sessionId: this.model.get('sessionId')
};
}

$.ajax({
type: 'POST',
url: OC.linkToOCS('apps/spreed/api/v1/room', 2) + OCA.SpreedMe.app.activeRoom.get('token') + '/moderators',
data: {
participant: participantId
},
data: data,
success: function() {
self.model.set('participantType', OCA.SpreedMe.app.MODERATOR);
if (self.model.get('userId')) {
self.model.set('participantType', OCA.SpreedMe.app.MODERATOR);
} else {
self.model.set('participantType', OCA.SpreedMe.app.GUEST_MODERATOR);
}
// When an attribute that affects the order of a
// collection is set the collection has to be explicitly
// sorted again.
Expand All @@ -214,25 +243,38 @@
});
},
demoteFromModerator: function() {
if (this.model.get('participantType') !== OCA.SpreedMe.app.MODERATOR) {
if (this.model.get('participantType') !== OCA.SpreedMe.app.MODERATOR &&
this.model.get('participantType') !== OCA.SpreedMe.app.GUEST_MODERATOR) {
return;
}

this.closeMenu();
this.ui.menuButton.addClass('hidden');
this.ui.menuButtonIconLoading.removeClass('hidden');

var participantId = this.model.get('userId'),
var data = {},
self = this;

if (this.model.get('userId')) {
data = {
participant: this.model.get('userId')
};
} else {
data = {
sessionId: this.model.get('sessionId')
};
}

$.ajax({
type: 'DELETE',
url: OC.linkToOCS('apps/spreed/api/v1/room', 2) + OCA.SpreedMe.app.activeRoom.get('token') + '/moderators',
data: {
participant: participantId
},
data:data,
success: function() {
self.model.set('participantType', OCA.SpreedMe.app.USER);
if (self.model.get('userId')) {
self.model.set('participantType', OCA.SpreedMe.app.USER);
} else {
self.model.set('participantType', OCA.SpreedMe.app.GUEST);
}
// When an attribute that affects the order of a
// collection is set the collection has to be explicitly
// sorted again.
Expand All @@ -259,7 +301,8 @@
participantId = this.model.get('userId'),
endpoint = '/participants';

if (this.model.get('participantType') === OCA.SpreedMe.app.GUEST) {
if (this.model.get('participantType') === OCA.SpreedMe.app.GUEST ||
this.model.get('participantType') === OCA.SpreedMe.app.GUEST_MODERATOR) {
participantId = this.model.get('sessionId');
endpoint += '/guests';
}
Expand Down
9 changes: 9 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,15 @@ protected function registerSignalingBackendHooks(EventDispatcherInterface $dispa
// so they can update the room properties.
$notifier->roomModified($room);
});
$dispatcher->addListener(Room::class . '::postSetParticipantTypeBySession', function(GenericEvent $event) {
/** @var BackendNotifier $notifier */
$notifier = $this->getBackendNotifier();

$room = $event->getSubject();
// The type of a participant has changed, notify all participants
// so they can update the room properties.
$notifier->roomModified($room);
});
$dispatcher->addListener(Room::class . '::postDeleteRoom', function(GenericEvent $event) {
/** @var BackendNotifier $notifier */
$notifier = $this->getBackendNotifier();
Expand Down
4 changes: 3 additions & 1 deletion lib/Chat/MessageParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

namespace OCA\Spreed\Chat;

use OCA\Spreed\Room;
use OCP\Comments\IComment;
use OCP\IL10N;
use OCP\IUser;
Expand All @@ -41,8 +42,9 @@ public function __construct(EventDispatcherInterface $dispatcher) {
$this->dispatcher = $dispatcher;
}

public function parseMessage(IComment $chatMessage, IL10N $l, IUser $user = null): array {
public function parseMessage(Room $room, IComment $chatMessage, IL10N $l, IUser $user = null): array {
$event = new GenericEvent($chatMessage, [
'room' => $room,
'user' => $user,
'l10n' => $l,
]);
Expand Down
28 changes: 27 additions & 1 deletion lib/Chat/Parser/SystemMessage.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ class SystemMessage {

/** @var null|IUser */
protected $recipient;
/** @var null|string */
protected $sessionId;
/** @var string[] */
protected $displayNames = [];
/** @var string[] */
Expand All @@ -79,6 +81,13 @@ public function __construct(IUserManager $userManager,
public function setUserInfo(IL10N $l, IUser $user = null) {
$this->l = $l;
$this->recipient = $user;
$this->sessionId = null;
}

public function setGuestInfo(IL10N $l, string $sessionId = null) {
$this->l = $l;
$this->recipient = null;
$this->sessionId = $sessionId;
}

/**
Expand All @@ -95,7 +104,8 @@ public function parseMessage(IComment $comment): array {
$message = $data['message'];
$parameters = $data['parameters'];
$parsedParameters = ['actor' => $this->getActor($comment)];
$currentUserIsActor = $this->recipient instanceof IUser && $this->recipient->getUID() === $parsedParameters['actor']['id'];
$currentUserIsActor = ($this->recipient instanceof IUser && $parsedParameters['actor']['type'] === 'user' && $this->recipient->getUID() === $parsedParameters['actor']['id']) ||
($this->sessionId !== null && $parsedParameters['actor']['type'] === 'guest' && $this->sessionId === $parsedParameters['actor']['id']);

if ($message === 'conversation_created') {
$parsedMessage = $this->l->t('{actor} created the conversation');
Expand Down Expand Up @@ -180,6 +190,22 @@ public function parseMessage(IComment $comment): array {
} else if ($this->recipient instanceof IUser && $this->recipient->getUID() === $parsedParameters['user']['id']) {
$parsedMessage = $this->l->t('{actor} demoted you from moderator');
}
} else if ($message === 'guest_moderator_promoted') {
$parsedParameters['user'] = $this->getGuest($parameters['session']);
$parsedMessage = $this->l->t('{actor} promoted {user} to moderator');
if ($currentUserIsActor) {
$parsedMessage = $this->l->t('You promoted {user} to moderator');
} else if ($this->sessionId !== null && $this->sessionId === $parsedParameters['user']['id']) {
$parsedMessage = $this->l->t('{actor} promoted you to moderator');
}
} else if ($message === 'guest_moderator_demoted') {
$parsedParameters['user'] = $this->getGuest($parameters['session']);
$parsedMessage = $this->l->t('{actor} demoted {user} from moderator');
if ($currentUserIsActor) {
$parsedMessage = $this->l->t('You demoted {user} from moderator');
} else if ($this->sessionId !== null && $this->sessionId === $parsedParameters['user']['id']) {
$parsedMessage = $this->l->t('{actor} demoted you from moderator');
}
} else if ($message === 'file_shared') {
try {
$parsedParameters['file'] = $this->getFileFromShare($parameters['share']);
Expand Down
Loading

0 comments on commit 546526a

Please sign in to comment.