From 12b7f32e14106283f306a3433f4402e9b3052969 Mon Sep 17 00:00:00 2001 From: Daniel Berteaud Date: Wed, 4 Jun 2014 16:00:29 +0200 Subject: [PATCH] Add a "promote to owner" button Fix #58 --- lib/Vroom/I18N/en.pm | 9 ++++++- lib/Vroom/I18N/fr.pm | 10 +++++++- public/css/vroom.css | 4 +++ public/js/vroom.js | 55 ++++++++++++++++++++++++++++++++++++++++++ public/vroom.pl | 37 ++++++++++++++++++++++++++++ templates/default/join.html.ep | 3 +++ 6 files changed, 116 insertions(+), 2 deletions(-) diff --git a/lib/Vroom/I18N/en.pm b/lib/Vroom/I18N/en.pm index faf55bf..1a7e134 100644 --- a/lib/Vroom/I18N/en.pm +++ b/lib/Vroom/I18N/en.pm @@ -161,13 +161,16 @@ our %Lexicon = ( "HELP_ASK_FOR_NAME_BUTTON" => "This will enforce participants to set their name before joining the room.", "HELP_LOGOUT_BUTTON" => "This will end the call and disconnect you from the room", "HELP_PEER_ACTIONS_BUTTONS" => "This menu will appear when you put the mouse over a video preview. It'll allow " . - "you to run actions which only affect this peer (mute/suspend/kick from the room)", + "you to run actions which only affect this peer (mute/suspend/grant admin rights/kick " . + "from the room). Warning: grating admin rights to someone is irrevocable, and he will " . + "be able to change configuration parameters (including passwords).", "LOGOUT" => "Leave the room", "SET_YOUR_NAME_TO_CHAT" => "You need to set your name to be able to chat", "SEND_MESSAGE" => "Send the message", "SAVE_HISTORY" => "Save history to a file", "MUTE_PEER" => "Mute or unmute this participant's microphone", "SUSPEND_PEER" => "Suspend or resume this participant's webcam", + "PROMOTE_PEER" => "Grant this participant administration privileges on the room", "KICK_PEER" => "Kick this participant out of the room", "s_IS_MUTING_YOU" => "%s has muted your microphone", "s_IS_MUTING_s" => "%s has muted %s's microphone", @@ -177,6 +180,9 @@ our %Lexicon = ( "s_IS_SUSPENDING_s" => "%s has suspended %s's webcam", "s_IS_RESUMING_YOU" => "%s has resumed your webcam", "s_IS_RESUMING_s" => "%s has resumed %s's webcam", + "s_IS_PROMOTING_YOU" => "%s has granted you administration privileges on the room", + "s_IS_PROMOTING_s" => "%s has granted %s administration privileges on the room", + "PEER_PROMOTED" => "You have granted administration privileges on the room", "s_IS_KICKING_s" => "%s has kicked %s out of the room", "KICKED" => "Kicked", "YOU_HAVE_BEEN_KICKED" => "You've been kicked out of the room", @@ -189,6 +195,7 @@ our %Lexicon = ( "CANT_SUSPEND_OWNER" => "You can't suspend this participant's webcam", "YOU_HAVE_KICKED_s" => "You have kicked %s out of the room", "CANT_KICK_OWNER" => "You can't kick this participant out of the room", + "CANT_PROMOTE_OWNER" => "This participant already has administration privileges on the room", "A_ROOM_ADMIN" => "a room administrator", "A_PARTICIPANT" => "a participant", "MIC_MUTED" => "Your microphone is now muted", diff --git a/lib/Vroom/I18N/fr.pm b/lib/Vroom/I18N/fr.pm index 5909896..aa1ab45 100644 --- a/lib/Vroom/I18N/fr.pm +++ b/lib/Vroom/I18N/fr.pm @@ -181,13 +181,17 @@ our %Lexicon = ( "HELP_LOGOUT_BUTTON" => "Ce bouton vous déconnectera du système", "HELP_PEER_ACTIONS_BUTTONS" => "Ce menu s'affiche en passant la souris au dessus d'une vignette vidéo. Il " . "vous permet d'effectuer certaines actions qui ne concerneront que cette " . - "personne (coupé le micro, mettre la webcam en pause, et bannir du salon)", + "personne (coupé le micro, mettre la webcam en pause, donner les droits " . + "d'administration sur le salon et bannir du salon). Attention: donner les droits " . + "d'administration à quelqu'un est irrévocable, et il pourra modifier tous les " . + "paramètres (y compris les mots de passe).", "LOGOUT" => "Quitter le salon", "SET_YOUR_NAME_TO_CHAT" => "Vous devez saisir votre nom avant de pouvoir tchater", "SEND_MESSAGE" => "Envoyer le message", "SAVE_HISTORY" => "Sauvegarder l'historique dans un fichier", "MUTE_PEER" => "Couper ou réactiver le micro de ce participant", "SUSPEND_PEER" => "Mettre en pause ou réactiver la webcam de ce participant", + "PROMOTE_PEER" => "Donner les droits d'administration du salon à ce participant", "KICK_PEER" => "Éjecter ce participant du salon", "s_IS_MUTING_YOU" => "%s a coupé votre micro", "s_IS_MUTING_s" => "%s a coupé le micro de %s", @@ -197,6 +201,9 @@ our %Lexicon = ( "s_IS_SUSPENDING_s" => "%s a mis la webcam de %s en pause", "s_IS_RESUMING_YOU" => "%s a réactivé votre webcam", "s_IS_RESUMING_s" => "%s a réactivé la webcam de %s", + "s_IS_PROMOTING_YOU" => "%s vous a donné les droits d'administration du salon", + "s_IS_PROMOTING_s" => "%s a donné les droits d'administration du salon à %s", + "PEER_PROMOTED" => "Vous avez donné les droits sur ce salon", "s_IS_KICKING_s" => "%s a éjecté %s du salon", "KICKED" => "Éjecté", "YOU_HAVE_BEEN_KICKED" => "Vous avez été banni du salon", @@ -209,6 +216,7 @@ our %Lexicon = ( "CANT_SUSPEND_OWNER" => "Vous ne pouvez pas mettre la webcam de ce participant en pause", "YOU_HAVE_KICKED_s" => "Vous avez bani %s du salon", "CANT_KICK_OWNER" => "Vous ne pouvez pas bannir ce participant", + "CANT_PROMOTE_OWNER" => "Ce participant dispose déjà des droits d'administration", "A_ROOM_ADMIN" => "un administrateur du salon", "A_PARTICIPANT" => "un participant", "MIC_MUTED" => "Votre micro est coupé", diff --git a/public/css/vroom.css b/public/css/vroom.css index a4a4cbd..3b949d9 100644 --- a/public/css/vroom.css +++ b/public/css/vroom.css @@ -125,6 +125,10 @@ font-family: 'Glyphicons Halflings'; content: "\e106"; } +.actionPromote:before{ + font-family: 'Glyphicons Halflings'; + content: "\e124"; +} .actionKick:before{ font-family: 'Glyphicons Halflings'; content: "\e083"; diff --git a/public/js/vroom.js b/public/js/vroom.js index 74318c6..5529071 100644 --- a/public/js/vroom.js +++ b/public/js/vroom.js @@ -51,9 +51,12 @@ var locale = { s_IS_SUSPENDING_s: '', s_IS_RESUMING_YOU: '', s_IS_RESUMING_s: '', + s_IS_PROMOTING_YOU: '', + s_IS_PROMOTING_s: '', s_IS_KICKING_s: '', MUTE_PEER: '', SUSPEND_PEER: '', + PROMOTE_PEER: '', KICK_PEER: '', YOU_HAVE_MUTED_s: '', YOU_HAVE_UNMUTED_s: '', @@ -61,6 +64,7 @@ var locale = { YOU_HAVE_SUSPENDED_s: '', YOU_HAVE_RESUMED_s: '', CANT_SUSPEND_OWNER: '', + CANT_PROMOTE_OWNER: '', YOU_HAVE_KICKED_s: '', CANT_KICK_OWNER: '', REMOVE_THIS_ADDRESS: '', @@ -539,6 +543,11 @@ function initVroom(room) { click: function() { pausePeer(id) }, }).prop('title', locale.SUSPEND_PEER)) .append($('', { + class: 'actionPromote btn btn-default btn-sm', + id: 'actionPromote_' + id, + click: function() { promotePeer(id) }, + }).prop('title', locale.PROMOTE_PEER)) + .append($('', { class: 'actionKick btn btn-default btn-sm', id: 'actionKick_' + id, click: function() { kickPeer(id) }, @@ -723,6 +732,34 @@ function initVroom(room) { $.notify(locale.CANT_SUSPEND_OWNER, 'error'); } } + // Promote a peer (he will be owner) + function promotePeer(id){ + if (peers[id] && peers[id].role != 'owner'){ + $.ajax({ + data: { + action: 'promote', + room: roomName, + peer: id + }, + error: function(data) { + $.notify(locale.ERROR_OCCURRED, 'error'); + }, + success: function(data) { + if (data.status == 'success' && data.msg){ + webrtc.sendToAll('owner_promoted', {peer: id}); + $.notify(data.msg, 'success'); + } + else if (data.msg){ + $.notify(data.msg, 'error'); + } + } + }); + suspendButton($('#actionPromote_' + id)); + } + else if (peers[id]){ + $.notify(locale.CANT_PROMOTE_OWNER, 'error'); + } + } // Kick a peer function kickPeer(id){ if (peers[id] && peers[id].role != 'owner'){ @@ -848,6 +885,24 @@ function initVroom(room) { } } }); + + // An owner has just promoted a participant of the room to the owner role + webrtc.on('owner_promoted', function(data){ + if (peers[data.id].role != 'owner' || data.roomType == 'screen'){ + return; + } + if (data.payload.peer && data.payload.peer == peers.local.id && peers.local.role != 'owner'){ + var who = (peers[data.id].hasName) ? peers[data.id].displayName : locale.A_ROOM_ADMIN; + $.notify(sprintf(locale.s_IS_PROMOTING_YOU, who), 'success'); + getRoomInfo(); + } + else if (data.payload.peer != peers.local.id && peers[data.payload.peer]){ + var who = (peers[data.id].hasName) ? peers[data.id].displayName : locale.A_ROOM_ADMIN; + var target = (peers[data.payload.peer].hasName) ? peers[data.payload.peer].displayName : locale.A_PARTICIPANT; + $.notify(sprintf(locale.s_IS_PROMOTING_s, who, target), 'info'); + } + }); + // An owner is kicking someone out of the room webrtc.on('owner_kick', function(data){ if (peers[data.id].role != 'owner' || data.roomType == 'screen'){ diff --git a/public/vroom.pl b/public/vroom.pl index f1a26b7..92ab968 100755 --- a/public/vroom.pl +++ b/public/vroom.pl @@ -279,6 +279,18 @@ helper get_peer_role => sub { } }; +# Promote a peer to owner +helper promote_peer => sub { + my $self = shift; + my ($room,$id) = @_; + my $sth = eval { $self->db->prepare("SELECT * FROM `participants` WHERE `peer_id`=? AND `id` IN (SELECT `id` FROM `rooms` WHERE `name`=?)") } || return undef; + $sth->execute($id,$room) || return undef; + return undef if ($sth->rows != 1); + $sth = eval { $self->db->prepare("UPDATE `participants` SET `role`='owner' WHERE `peer_id`=? AND `id` IN (SELECT `id` FROM `rooms` WHERE `name`=?)") } || return undef; + $sth->execute($id,$room) || return undef; + return 1; +}; + # Check if a participant has joined a room # Takes two args: the session name, and the room name helper has_joined => sub { @@ -1013,6 +1025,9 @@ post '/action' => sub { my $res = 'error'; my %emailNotif; if ($self->session($room) && $self->session($room)->{role}){ + if ($self->session($room)->{role} ne 'owner' && $self->get_peer_role($room,$id) eq 'owner'){ + $self->session($room)->{role} = 'owner'; + } $res = ($self->set_peer_role($room,$self->session('name'),$id, $self->session($room)->{role})) ? 'success':$res; } if ($self->session($room)->{role} eq 'owner'){ @@ -1117,6 +1132,28 @@ post '/action' => sub { } ); } + # A participant is being promoted to the owner status + elsif ($action eq 'promote'){ + my $peer = $self->param('peer'); + my $status = 'error'; + my $msg = $self->l('ERROR_OCCURRED'); + if (!$peer){ + $msg = $self->l('ERROR_OCCURRED'); + } + elsif ($self->session($room)->{role} ne 'owner'){ + $msg = $self->l('NOT_ALLOWED'); + } + elsif ($self->promote_peer($room,$peer)){ + $status = 'success'; + $msg = $self->l('PEER_PROMOTED'); + } + return $self->render( + json => { + msg => $msg, + status => $status + } + ); + } }; # use the templates defined in the config diff --git a/templates/default/join.html.ep b/templates/default/join.html.ep index e6abd1e..d26ad5f 100644 --- a/templates/default/join.html.ep +++ b/templates/default/join.html.ep @@ -495,6 +495,9 @@
+ +
+