Separate owner password and persistence

Now, persistent rooms will be really persistent (never deleted), but can only be set by an admin
Rooms with an owner password set are now called "reserved" room, and works as before
master
Daniel Berteaud 10 years ago
parent a2b19cbeb8
commit a289803632
  1. 7
      conf/vroom.conf.sample
  2. 33
      lib/Vroom/I18N/en.pm
  3. 30
      lib/Vroom/I18N/fr.pm
  4. 45
      public/js/vroom.js
  5. 63
      public/vroom.pl
  6. 4
      templates/default/help.html.ep
  7. 6
      templates/default/join.html.ep
  8. 12
      templates/default/manage_room.html.ep
  9. 18
      templates/default/owner_password_modal.html.ep

@ -23,10 +23,11 @@ secret => 'ChangeMe!',
# App # App
# Rooms without any activity for that long (in seconds) will be destroyed # Rooms without any activity for that long (in seconds) will be destroyed
inactivityTimeout => 3600, inactivityTimeout => 3600,
# Inactivity timeout (in seconds) for persistent rooms # Inactivity timeout (in seconds) for rooms which have an owner password
# 0 means they are not deleted. You can use a high number # 0 means they are not deleted. You can use a high number
# so that persistent rooms are kept long enough, but deleted when not used # so that those rooms are kept long enough, but deleted when really not used
persistentInactivityTimeout => 0, # The admin interface lets you flag some room as persistent, meaning they will never be deleted
reservedInactivityTimeout => 0,
# A list of room names which are valid but too common to allow reservation # A list of room names which are valid but too common to allow reservation
# with an owner password # with an owner password
commonRoomNames => [ commonRoomNames => [

@ -122,16 +122,16 @@ our %Lexicon = (
"PASSWORD_PROTECT" => "Password protect", "PASSWORD_PROTECT" => "Password protect",
"PASSWORD_PROTECT_SET" => "A password will be needed to join this room", "PASSWORD_PROTECT_SET" => "A password will be needed to join this room",
"PASSWORD_PROTECT_UNSET" => "No password will be asked to join this room", "PASSWORD_PROTECT_UNSET" => "No password will be asked to join this room",
"ROOM_NOW_PERSISTENT" => "This room is now persistent", "ROOM_NOW_RESERVED" => "This room is now reserved",
"ROOM_NO_MORE_PERSISTENT" => "This room isn't persistent anymore", "ROOM_NO_MORE_RESERVED" => "This room isn't reserved anymore",
"PASSWORDS_DO_NOT_MATCH" => "Passwords do not match", "PASSWORDS_DO_NOT_MATCH" => "Passwords do not match",
"MAKE_THIS_ROOM_PERSISTENT" => "Make this room persistent", "RESERVE_THIS_ROOM" => "Reserve this room",
"SET_OWNER_PASS_PERSISTENT" => "To make this room persistent, you must set a manager password. Keep it carefully, " . "SET_OWNER_PASS" => "To reserve this room, you must set an owner password. Keep it carefully, " .
"it'll grant you access to the configuration menus next time you connect.", "it'll grant you access to the configuration menus next time you connect.",
"A_STANDARD_ROOM_EXPIRES_AFTER_d" => "A standard room will be deleted after %d hour(s) without activity", "A_STANDARD_ROOM_EXPIRES_AFTER_d" => "A standard room will be deleted after %d hour(s) without activity",
"A_PERSISTENT_ROOM" => "A persistant room", "A_RESERVED_ROOM" => "A reserved room",
"EXPIRE_AFTER_d" => "will be deleted after %d day(s) without activity", "EXPIRE_AFTER_d" => "will be deleted after %d day(s) without activity",
"NEVER_EXPIRE" => "will be kept forever", "WILL_NEVER_EXPIRE" => "will be kept forever",
"CONFIRM_PASSWORD" => "Confirm password", "CONFIRM_PASSWORD" => "Confirm password",
"PROTECT_ROOM_WITH_PASSWORD" => "If this password is set, participants will have to type it before the system let them in", "PROTECT_ROOM_WITH_PASSWORD" => "If this password is set, participants will have to type it before the system let them in",
"ERROR_COMMON_ROOM_NAME" => "Sorry, this room name is too comon to be reserved", "ERROR_COMMON_ROOM_NAME" => "Sorry, this room name is too comon to be reserved",
@ -167,8 +167,11 @@ our %Lexicon = (
"NUMBER_OF_PARTICIPANTS" => "Number of participants", "NUMBER_OF_PARTICIPANTS" => "Number of participants",
"LOCKED" => "Locked", "LOCKED" => "Locked",
"ASK_FOR_NAME" => "Require to enter a name", "ASK_FOR_NAME" => "Require to enter a name",
"PASSWORD_PROTECTED" => "Password protection", "JOIN_PASSWORD" => "Password to join the room",
"OWNER_PASSWORD" => "Password to manage the room",
"PERSISTENT" => "Persistent", "PERSISTENT" => "Persistent",
"ROOM_NOW_PERSISTENT" => "This room is now persistent",
"ROOM_NO_MORE_PERSISTENT" => "This rooms isn't persistent anymore",
"EMAIL_INVITE" => "Email invitation", "EMAIL_INVITE" => "Email invitation",
"DELETE_THIS_ROOM" => "Delete this room", "DELETE_THIS_ROOM" => "Delete this room",
"CONFIRM_DELETE" => "Confirm delation", "CONFIRM_DELETE" => "Confirm delation",
@ -194,7 +197,7 @@ our %Lexicon = (
"HELP_PASSWORD_BUTTON" => "This button will protect access to this room with a password. Note that this password " . "HELP_PASSWORD_BUTTON" => "This button will protect access to this room with a password. Note that this password " .
"isn't asked it you join the room through an email invitation (in which case the " . "isn't asked it you join the room through an email invitation (in which case the " .
"authentication is done with a uniq token valid for two hours)", "authentication is done with a uniq token valid for two hours)",
"HELP_PERSISTENT_BUTTON" => "Make this room persistent, you'll be able to leave, reconnecte, and get configuration menus back. " . "HELP_RESERVE_BUTTON" => "Reserve this room, you'll be able to leave, reconnect, and get configuration menus back. " .
"The room will also be kept much longer.", "The room will also be kept much longer.",
"HELP_ASK_FOR_NAME_BUTTON" => "This will enforce participants to set their name before joining the room.", "HELP_ASK_FOR_NAME_BUTTON" => "This will enforce participants to set their name before joining the room.",
"HELP_WIPE_DATA_BUTTON" => "This will wipe room data (chat history and collaborative pad content)", "HELP_WIPE_DATA_BUTTON" => "This will wipe room data (chat history and collaborative pad content)",
@ -321,15 +324,15 @@ our %Lexicon = (
"later, which are simple participants). For example, he can protect access with a password " . "later, which are simple participants). For example, he can protect access with a password " .
"which will be required before you can join the room. He also can set the manager's password " . "which will be required before you can join the room. He also can set the manager's password " .
"which will allow him, if he leaves the room, to recover its privileges when he connects again.", "which will allow him, if he leaves the room, to recover its privileges when he connects again.",
"PERSISTENT_ROOMS" => "Persistant rooms", "RESERVED_ROOMS" => "Reserved rooms",
"HELP_PERSISTENT_ROOMS" => "By default, rooms are ephemeral, which means they are automatically deleted if they " . "HELP_RESERVED_ROOMS" => "By default, rooms are ephemeral, which means they are automatically deleted if they " .
"have no activity for a long time. The room's creator can define a manager's password, " . "have no activity for some time. The room's creator can define an owner's password, " .
"which will make the room persistent. Note that a persistent room can still be deleted " . "which will make the room reserved. A reserved room can still be deleted " .
"if it's not used for a very long period of time.", "if it's not used for a very long period of time, but will last longuer on the system",
"RESERVE_YOUR_ROOM" => "Reserve your room", "RESERVE_YOUR_ROOM" => "Reserve your room",
"HELP_RESERVE_YOUR_ROOM" => "Want to reserve your room name so it's always available for you (company name, ongoing project " . "HELP_RESERVE_YOUR_ROOM" => "Want to reserve your room name so it's always available for you (company name, ongoing project " .
"etc.) ? Just set both a join password and the manager password. The room will be kept " . "etc.) ? Just set both a join password and the owner password. The room will be kept " .
"as long as the manager password is set (and as long as you use it from time to time)", "as long as the owner password is set (and as long as you use it from time to time)",
"BE_NOTIFIED" => "Notifications", "BE_NOTIFIED" => "Notifications",
"HELP_BE_NOTIFIED" => "You can be notified by email as soon as someone joins one of your rooms. For example, " . "HELP_BE_NOTIFIED" => "You can be notified by email as soon as someone joins one of your rooms. For example, " .
"create a room, add a password to make it persistent and add the link in your email signature. " . "create a room, add a password to make it persistent and add the link in your email signature. " .

@ -128,17 +128,17 @@ our %Lexicon = (
"PASSWORD_PROTECT" => "Protéger par mot de passe", "PASSWORD_PROTECT" => "Protéger par mot de passe",
"PASSWORD_PROTECT_SET" => "Un mot de passe sera demandé pour rejoindre ce salon", "PASSWORD_PROTECT_SET" => "Un mot de passe sera demandé pour rejoindre ce salon",
"PASSWORD_PROTECT_UNSET" => "Aucun mot de passe ne sera demandé pour rejoindre ce salon", "PASSWORD_PROTECT_UNSET" => "Aucun mot de passe ne sera demandé pour rejoindre ce salon",
"ROOM_NOW_PERSISTENT" => "Ce salon est maintenant persistant", "ROOM_NOW_RESERVED" => "Ce salon est maintenant réservé",
"ROOM_NO_MORE_PERSISTENT" => "Ce salon n'est plus persistant", "ROOM_NO_MORE_RESERVED" => "Ce salon ne vous est plus réservé",
"PASSWORDS_DO_NOT_MATCH" => "Les mots de passe ne correspondent pas", "PASSWORDS_DO_NOT_MATCH" => "Les mots de passe ne correspondent pas",
"MAKE_THIS_ROOM_PERSISTENT" => "Rendre ce salon persistant", "RESERVE_THIS_ROOM" => "Réserver ce salon",
"SET_OWNER_PASS_PERSISTENT" => "Pour rendre ce salon persistant, vous devez saisir un mot de passe. " . "SET_OWNER_PASS" => "Pour réserver ce salon, vous devez saisir un mot de passe. " .
"Conservez le soigneusement, il vous permettra de retrouver " . "Conservez le soigneusement, il vous permettra de retrouver " .
"l'accès aux menus de configuration quand vous vous reconnecterez.", "l'accès aux menus de configuration quand vous vous reconnecterez.",
"A_STANDARD_ROOM_EXPIRES_AFTER_d" => "Un salon classique sera détruit après %d heure(s) sans activité", "A_STANDARD_ROOM_EXPIRES_AFTER_d" => "Un salon classique sera détruit après %d heure(s) sans activité",
"A_PERSISTENT_ROOM" => "Un salon persistant", "A_RESERVED_ROOM" => "Un salon réservé",
"EXPIRE_AFTER_d" => "sera détruit après %d jour(s) sans activité", "EXPIRE_AFTER_d" => "sera détruit après %d jour(s) sans activité",
"NEVER_EXPIRE" => "sera conservé indéfiniement", "WILL_NEVER_EXPIRE" => "sera conservé indéfiniement",
"CONFIRM_PASSWORD" => "Confirmation du mot de passe", "CONFIRM_PASSWORD" => "Confirmation du mot de passe",
"PROTECT_ROOM_WITH_PASSWORD" => "Si ce mot de passe est configuré, les participants devront le saisir avant de pouvoir " . "PROTECT_ROOM_WITH_PASSWORD" => "Si ce mot de passe est configuré, les participants devront le saisir avant de pouvoir " .
"rejoindre le salon", "rejoindre le salon",
@ -174,8 +174,11 @@ our %Lexicon = (
"NUMBER_OF_PARTICIPANTS" => "Nombre de participants", "NUMBER_OF_PARTICIPANTS" => "Nombre de participants",
"LOCKED" => "Verrouillé", "LOCKED" => "Verrouillé",
"ASK_FOR_NAME" => "Exige de saisir un nom", "ASK_FOR_NAME" => "Exige de saisir un nom",
"PASSWORD_PROTECTED" => "Protection par mot de passe", "JOIN_PASSWORD" => "Mot de passe d'accès au salon",
"OWNER_PASSWORD" => "Mot de passe de gestionnaire",
"PERSISTENT" => "Persistant", "PERSISTENT" => "Persistant",
"ROOM_NOW_PERSISTENT" => "Ce salon est maintenant persistant",
"ROOM_NO_MORE_PERSISTENT" => "Ce salon n'est plus persistant",
"EMAIL_INVITE" => "Invitation par email", "EMAIL_INVITE" => "Invitation par email",
"DELETE_THIS_ROOM" => "Supprimer ce salon", "DELETE_THIS_ROOM" => "Supprimer ce salon",
"CONFIRM_DELETE" => "Confirmer la suppression", "CONFIRM_DELETE" => "Confirmer la suppression",
@ -213,7 +216,7 @@ our %Lexicon = (
"pas demandé lorsque l'on " . "pas demandé lorsque l'on " .
"rejoint un salon suite à une invitation par email (l'authentification se fait " . "rejoint un salon suite à une invitation par email (l'authentification se fait " .
"par un jeton unique valide pendant deux heures", "par un jeton unique valide pendant deux heures",
"HELP_PERSISTENT_BUTTON" => "Permet de rendre le salon persistant. Vous pourrez donc vous reconnecter et " . "HELP_RESERVE_BUTTON" => "Permet de réserver le salon. Vous pourrez donc vous reconnecter et " .
"récupérer l'accès aux menus de configuration. Le salon sera également conservé " . "récupérer l'accès aux menus de configuration. Le salon sera également conservé " .
"bien plus longtemps sur le système", "bien plus longtemps sur le système",
"HELP_ASK_FOR_NAME_BUTTON" => "Permet d'imposer la saisie du nom avant de pouvoir rejoindre le salon", "HELP_ASK_FOR_NAME_BUTTON" => "Permet d'imposer la saisie du nom avant de pouvoir rejoindre le salon",
@ -356,12 +359,13 @@ our %Lexicon = (
"de passe du gestionnaire ce qui lui permettra, s'il quitte le salon, de retrouver " . "de passe du gestionnaire ce qui lui permettra, s'il quitte le salon, de retrouver " .
"ses privilèges lorsqu'il se connecte à nouveau. Ces privilèges peuvent aussi être " . "ses privilèges lorsqu'il se connecte à nouveau. Ces privilèges peuvent aussi être " .
"donnés à d'autres participants", "donnés à d'autres participants",
"PERSISTENT_ROOMS" => "Salons persistants", "RESERVED_ROOMS" => "Salons réservés",
"HELP_PERSISTENT_ROOMS" => "Par défaut, les salons sont éphémères, c'est à dire qu'ils sont automatiquement " . "HELP_RESERVED_ROOMS" => "Par défaut, les salons sont éphémères, c'est à dire qu'ils sont automatiquement " .
"supprimés si ils ne présentent aucune activité pendant une durée prolongée. " . "supprimés si ils ne présentent aucune activité pendant un certains temps. " .
"Le créateur du salon peut définir un mot de passe de gestionaire, ce qui " . "Le créateur du salon peut définir un mot de passe de gestionaire, ce qui " .
"rendra le salon persistant. Notez qu'un salon persistant peut tout de même " . "rendra réservera le salon. Un salon réservé peut tout de même " .
"être supprimé si il n'est pas utilisé pendant une très longue période.", "être supprimé si il n'est pas utilisé pendant une très longue période, mais le " .
"délais sera bien plus long.",
"RESERVE_YOUR_ROOM" => "Réservez votre salon", "RESERVE_YOUR_ROOM" => "Réservez votre salon",
"HELP_RESERVE_YOUR_ROOM" => "Vous souhaitez réserver le nom de votre salon pour qu'il soit toujours disponible " . "HELP_RESERVE_YOUR_ROOM" => "Vous souhaitez réserver le nom de votre salon pour qu'il soit toujours disponible " .
"pour vous (nom de votre entreprise, nom d'un projet en cours etc.) ? Configurez simplement " . "pour vous (nom de votre entreprise, nom d'un projet en cours etc.) ? Configurez simplement " .

@ -400,7 +400,7 @@ function initManage(){
} }
else if (param === 'ownerPassSwitch'){ else if (param === 'ownerPassSwitch'){
if (state){ if (state){
$('#persistentModal').modal('show'); $('#ownerPassModal').modal('show');
sw.bootstrapSwitch('toggleState', true); sw.bootstrapSwitch('toggleState', true);
} }
else{ else{
@ -409,6 +409,11 @@ function initManage(){
sendAction(data,sw); sendAction(data,sw);
} }
} }
else if (param === 'persistentSwitch'){
data.action = 'setPersistent';
data.type = (state) ? 'set' : 'unset';
sendAction(data,sw);
}
// Something isn't implemented yet ? // Something isn't implemented yet ?
else{ else{
$.notify(locale.ERROR_OCCURRED, 'error'); $.notify(locale.ERROR_OCCURRED, 'error');
@ -438,7 +443,7 @@ function initManage(){
} }
}); });
$('#persistentForm').submit(function(event) { $('#ownerPassForm').submit(function(event) {
event.preventDefault(); event.preventDefault();
var pass = $('#ownerPass').val(); var pass = $('#ownerPass').val();
var pass2 = $('#ownerPassConfirm').val(); var pass2 = $('#ownerPassConfirm').val();
@ -451,7 +456,7 @@ function initManage(){
data.password = pass data.password = pass
sendAction(data, $('#ownerPassSwitch')); sendAction(data, $('#ownerPassSwitch'));
$('#ownerPassSwitch').bootstrapSwitch('toggleState', true); $('#ownerPassSwitch').bootstrapSwitch('toggleState', true);
$('#persistentModal').modal('hide'); $('#ownerPassModal').modal('hide');
} }
else{ else{
$('#ownerPassConfirm').notify(locale.PASSWORDS_DO_NOT_MATCH, 'error'); $('#ownerPassConfirm').notify(locale.PASSWORDS_DO_NOT_MATCH, 'error');
@ -599,8 +604,8 @@ function initVroom(room) {
$('#joinPassButton').prop('checked', true); $('#joinPassButton').prop('checked', true);
} }
if (data.owner_auth == 'yes'){ if (data.owner_auth == 'yes'){
$('#persistentLabel').addClass('btn-danger active'); $('#ownerPassLabel').addClass('btn-danger active');
$('#persistentButton').prop('checked', true); $('#ownerPassButton').prop('checked', true);
} }
} }
}); });
@ -1430,13 +1435,13 @@ function initVroom(room) {
var who = (peers[data.id].hasName) ? peers[data.id].displayName : locale.A_ROOM_ADMIN; var who = (peers[data.id].hasName) ? peers[data.id].displayName : locale.A_ROOM_ADMIN;
if (data.payload.action == 'set'){ if (data.payload.action == 'set'){
$.notify(sprintf(locale.OWNER_PASSWORD_CHANGED_BY_s, stringEscape(who)), 'info'); $.notify(sprintf(locale.OWNER_PASSWORD_CHANGED_BY_s, stringEscape(who)), 'info');
$('#persistentLabel').addClass('btn-danger active'); $('#ownerPassLabel').addClass('btn-danger active');
$('#persistentButton').prop('checked', true); $('#ownerPassButton').prop('checked', true);
} }
else{ else{
$.notify(sprintf(locale.OWNER_PASSWORD_REMOVED_BY_s, stringEscape(who)), 'info'); $.notify(sprintf(locale.OWNER_PASSWORD_REMOVED_BY_s, stringEscape(who)), 'info');
$('#persistentLabel').removeClass('btn-danger active'); $('#ownerPassLabel').removeClass('btn-danger active');
$('#persistentButton').prop('checked', false); $('#ownerPassButton').prop('checked', false);
} }
} }
else{ else{
@ -1983,15 +1988,15 @@ function initVroom(room) {
} }
}); });
$('#persistentButton').change(function(){ $('#ownerPassButton').change(function(){
var action = ($(this).is(':checked')) ? 'set':'unset'; var action = ($(this).is(':checked')) ? 'set':'unset';
if (action == 'set'){ if (action == 'set'){
$('#persistentModal').modal('show'); $('#ownerPassModal').modal('show');
// Uncheck the button now // Uncheck the button now
// so it's not inconsistent if we just close the modal dialog // so it's not inconsistent if we just close the modal dialog
// submitting the form will recheck it // submitting the form will recheck it
$('#persistentButton').prop('checked', false); $('#ownerPassButton').prop('checked', false);
$('#persistentLabel').removeClass('active'); $('#ownerPassLabel').removeClass('active');
} }
else{ else{
$.ajax({ $.ajax({
@ -2008,7 +2013,7 @@ function initVroom(room) {
if (data.status == 'success'){ if (data.status == 'success'){
$.notify(data.msg, 'info'); $.notify(data.msg, 'info');
webrtc.sendToAll('owner_password', {action: 'remove'}); webrtc.sendToAll('owner_password', {action: 'remove'});
$('#persistentLabel').removeClass('btn-danger active'); $('#ownerPassLabel').removeClass('btn-danger active');
} }
else{ else{
$.notify(data.msg, 'error'); $.notify(data.msg, 'error');
@ -2019,7 +2024,7 @@ function initVroom(room) {
} }
}); });
$('#persistentForm').submit(function(event) { $('#ownerPassForm').submit(function(event) {
event.preventDefault(); event.preventDefault();
var pass = $('#ownerPass').val(); var pass = $('#ownerPass').val();
var pass2 = $('#ownerPassConfirm').val(); var pass2 = $('#ownerPassConfirm').val();
@ -2034,15 +2039,15 @@ function initVroom(room) {
}, },
error: function() { error: function() {
$.notify(locale.ERROR_OCCURRED, 'error'); $.notify(locale.ERROR_OCCURRED, 'error');
$('#persistentLabel').removeClass('btn-danger active'); $('#ownerPassLabel').removeClass('btn-danger active');
}, },
success: function(data) { success: function(data) {
$('#ownerPass').val(''); $('#ownerPass').val('');
$('#ownerPassConfirm').val(''); $('#ownerPassConfirm').val('');
if (data.status == 'success'){ if (data.status == 'success'){
$('#persistentModal').modal('hide'); $('#ownerPassModal').modal('hide');
$('#persistentLabel').addClass('btn-danger active'); $('#ownerPassLabel').addClass('btn-danger active');
$('#persistentButton').prop('checked', true); $('#ownerPassButton').prop('checked', true);
$.notify(data.msg, 'info'); $.notify(data.msg, 'info');
webrtc.sendToAll('owner_password', {action: 'set'}); webrtc.sendToAll('owner_password', {action: 'set'});
} }
@ -2224,7 +2229,7 @@ function initVroom(room) {
}); });
// Empty password fields on modal dismiss // Empty password fields on modal dismiss
$('#joinPassModal,#persistentModal').on('hide.bs.modal',function(){ $('#joinPassModal,#ownerPassModal').on('hide.bs.modal',function(){
$(this).find(':input').val(''); $(this).find(':input').val('');
}); });

@ -122,7 +122,7 @@ our $config = plugin Config => {
poweredBy => '<a href="http://www.firewall-services.com" target="_blank">Firewall Services</a>', poweredBy => '<a href="http://www.firewall-services.com" target="_blank">Firewall Services</a>',
template => 'default', template => 'default',
inactivityTimeout => 3600, inactivityTimeout => 3600,
persistentInactivityTimeout => 0, reservedInactivityTimeout => 5184000,
commonRoomNames => [ qw() ], commonRoomNames => [ qw() ],
logLevel => 'info', logLevel => 'info',
chromeExtensionId => 'ecicdpoejfllflombfanbhfpgcimjddn', chromeExtensionId => 'ecicdpoejfllflombfanbhfpgcimjddn',
@ -380,7 +380,7 @@ helper delete_rooms => sub {
$self->app->log->debug('Removing unused rooms'); $self->app->log->debug('Removing unused rooms');
my $timeout = time()-$config->{inactivityTimeout}; my $timeout = time()-$config->{inactivityTimeout};
my $sth = eval { my $sth = eval {
$self->db->prepare("SELECT `name` FROM `rooms` WHERE `activity_timestamp` < $timeout AND `persistent`='0';") $self->db->prepare("SELECT `name` FROM `rooms` WHERE `activity_timestamp` < $timeout AND `persistent`='0' AND `owner_password` IS NULL;")
} || return undef; } || return undef;
$sth->execute(); $sth->execute();
my @toDeleteName = (); my @toDeleteName = ();
@ -388,10 +388,10 @@ helper delete_rooms => sub {
push @toDeleteName, $room; push @toDeleteName, $room;
} }
my @toDeleteId = (); my @toDeleteId = ();
if ($config->{persistentInactivityTimeout} > 0){ if ($config->{reservedInactivityTimeout} > 0){
$timeout = time()-$config->{persistentInactivityTimeout}; $timeout = time()-$config->{reservedInactivityTimeout};
$sth = eval { $sth = eval {
$self->db->prepare("SELECT `name` FROM `rooms` WHERE `activity_timestamp` < $timeout AND `persistent`='1';") $self->db->prepare("SELECT `name` FROM `rooms` WHERE `activity_timestamp` < $timeout AND `persistent`='0' AND `owner_password` IS NOT NULL;")
} || return undef; } || return undef;
$sth->execute(); $sth->execute();
while (my $room = $sth->fetchrow_array){ while (my $room = $sth->fetchrow_array){
@ -560,21 +560,40 @@ helper set_owner_pass => sub {
# Might be separated in the future # Might be separated in the future
if ($pass){ if ($pass){
my $sth = eval { my $sth = eval {
$self->db->prepare("UPDATE `rooms` SET `owner_password`=?,`persistent`='1' WHERE `name`=?;") $self->db->prepare("UPDATE `rooms` SET `owner_password`=? WHERE `name`=?;")
} || return undef; } || return undef;
my $pass = Crypt::SaltedHash->new(algorithm => 'SHA-256')->add($pass)->generate; my $pass = Crypt::SaltedHash->new(algorithm => 'SHA-256')->add($pass)->generate;
$sth->execute($pass,$room) || return undef; $sth->execute($pass,$room) || return undef;
$self->app->log->debug($self->session('name') . " has set an owner password on room $room, which is now persistent"); $self->app->log->debug($self->session('name') . " has set an owner password on room $room");
} }
else{ else{
my $sth = eval { my $sth = eval {
$self->db->prepare("UPDATE `rooms` SET `owner_password`=?,`persistent`='0' WHERE `name`=?;") $self->db->prepare("UPDATE `rooms` SET `owner_password`=? WHERE `name`=?;")
} || return undef; } || return undef;
$sth->execute(undef,$room) || return undef; $sth->execute(undef,$room) || return undef;
$self->app->log->debug($self->session('name') . " has removed the owner password on room $room, which is not persistent anymore"); $self->app->log->debug($self->session('name') . " has removed the owner password on room $room");
} }
}; };
# Make the room persistent
helper set_persistent => sub {
my $self = shift;
my ($room,$set) = @_;
my $data = $self->get_room($room);
return undef unless ($data);
my $sth = eval {
$self->db->prepare("UPDATE `rooms` SET `persistent`=? WHERE `name`=?")
} || return undef;
$sth->execute($set,$room) || return undef;
if ($set eq '1'){
$self->app->log->debug("Room $room is now persistent");
}
else{
$self->app->log->debug("Room $room isn't persistent anymore");
}
return 1;
};
# Add an email address to the list of notifications # Add an email address to the list of notifications
helper add_notification => sub { helper add_notification => sub {
my $self = shift; my $self = shift;
@ -1238,7 +1257,7 @@ post '/*action' => [action => [qw/action admin\/action/]] => sub {
$msg = $self->l('ERROR_COMMON_ROOM_NAME'); $msg = $self->l('ERROR_COMMON_ROOM_NAME');
} }
elsif ($self->set_owner_pass($room,$pass)){ elsif ($self->set_owner_pass($room,$pass)){
$msg = ($pass) ? $self->l('ROOM_NOW_PERSISTENT') : $self->l('ROOM_NO_MORE_PERSISTENT'); $msg = ($pass) ? $self->l('ROOM_NOW_RESERVED') : $self->l('ROOM_NO_MORE_RESERVED');
$status = 'success'; $status = 'success';
} }
} }
@ -1258,6 +1277,30 @@ post '/*action' => [action => [qw/action admin\/action/]] => sub {
} }
); );
} }
# Handle persistence
elsif ($action eq 'setPersistent'){
my $type = $self->param('type');
my $status = 'error';
my $msg = $self->l('ERROR_OCCURRED');
# Only possible through /admin/action
if ($prefix ne 'admin'){
$msg = $self->l('NOT_ALLOWED');
}
elsif($type eq 'set' && $self->set_persistent($room,'1')){
$status = 'success';
$msg = $self->l('ROOM_NOW_PERSISTENT');
}
elsif($type eq 'unset' && $self->set_persistent($room,'0')){
$status = 'success';
$msg = $self->l('ROOM_NO_MORE_PERSISTENT');
}
return $self->render(
json => {
msg => $msg,
status => $status
}
);
}
# A participant is trying to auth as an owner, lets check that # A participant is trying to auth as an owner, lets check that
elsif ($action eq 'authenticate'){ elsif ($action eq 'authenticate'){
my $pass = $self->param('password'); my $pass = $self->param('password');

@ -64,13 +64,13 @@
<div class="panel-heading"> <div class="panel-heading">
<h4 class="panel-title"> <h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#collapsePersistentRooms"> <a data-toggle="collapse" data-parent="#accordion" href="#collapsePersistentRooms">
<%=l 'PERSISTENT_ROOMS' %> <%=l 'RESERVED_ROOMS' %>
</a> </a>
</h4> </h4>
</div> </div>
<div id="collapsePersistentRooms" class="panel-collapse collapse"> <div id="collapsePersistentRooms" class="panel-collapse collapse">
<div class="panel-body"> <div class="panel-body">
<%==l 'HELP_PERSISTENT_ROOMS' %> <%==l 'HELP_RESERVED_ROOMS' %>
</div> </div>
</div> </div>
</div> </div>

@ -159,8 +159,8 @@
<span class="glyphicon glyphicon-lock"> <span class="glyphicon glyphicon-lock">
</span> </span>
</label> </label>
<label class="btn btn-default help" id="persistentLabel" data-toggle="tooltip" data-placement="bottom" title="<%=l 'MAKE_THIS_ROOM_PERSISTENT' %>"> <label class="btn btn-default help" id="ownerPassLabel" data-toggle="tooltip" data-placement="bottom" title="<%=l 'RESERVE_THIS_ROOM' %>">
<input type="checkbox" id="persistentButton"> <input type="checkbox" id="ownerPassButton">
<span class="glyphicon glyphicon-pushpin"> <span class="glyphicon glyphicon-pushpin">
</span> </span>
</label> </label>
@ -472,7 +472,7 @@
</div> </div>
</div> </div>
<div class="col-md-10"> <div class="col-md-10">
<%=l 'HELP_PERSISTENT_BUTTON' %> <%=l 'HELP_RESERVE_BUTTON' %>
</div> </div>
</div> </div>
<div class="list-group-item row ownerEl"> <div class="list-group-item row ownerEl">

@ -90,7 +90,7 @@
</tr> </tr>
<tr> <tr>
<th> <th>
<%=l 'PASSWORD_PROTECTED' %> <%=l 'JOIN_PASSWORD' %>
</th> </th>
<th> <th>
<input class="bs-switch" type="checkbox" id="joinPassSwitch" data-room="<%= $room %>" <%= ($data->{join_password}) ? 'checked':''%>> <input class="bs-switch" type="checkbox" id="joinPassSwitch" data-room="<%= $room %>" <%= ($data->{join_password}) ? 'checked':''%>>
@ -98,7 +98,7 @@
</tr> </tr>
<tr> <tr>
<th> <th>
<%=l 'PERSISTENT' %> <%=l 'OWNER_PASSWORD' %>
</th> </th>
<th> <th>
<input class="bs-switch" type="checkbox" id="ownerPassSwitch" data-room="<%= $room %>" <%= ($data->{owner_password}) ? 'checked':''%>> <input class="bs-switch" type="checkbox" id="ownerPassSwitch" data-room="<%= $room %>" <%= ($data->{owner_password}) ? 'checked':''%>>
@ -106,6 +106,14 @@
</tr> </tr>
<tr> <tr>
<th> <th>
<%=l 'PERSISTENT' %>
</th>
<th>
<input class="bs-switch" type="checkbox" id="persistentSwitch" data-room="<%= $room %>" <%= ($data->{persistent}) ? 'checked':''%>>
</th>
</tr>
<tr>
<th>
<%=l 'EMAIL_INVITE' %> <%=l 'EMAIL_INVITE' %>
</th> </th>
<th> <th>

@ -1,28 +1,28 @@
<div class="modal fade" role="dialog" id="persistentModal" aria-labelledby="persistentModal" aria-hidden="true"> <div class="modal fade" role="dialog" id="ownerPassModal" aria-labelledby="ownerPassModal" aria-hidden="true">
<div class="modal-dialog modal-lg"> <div class="modal-dialog modal-lg">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">
&times; &times;
</button> </button>
<h4 class="modal-title" id="persistentTitle"> <h4 class="modal-title">
<%=l 'MAKE_THIS_ROOM_PERSISTENT' %> <%=l 'RESERVE_THIS_ROOM' %>
</h4> </h4>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form class="form-horizontal" role="form" id="persistentForm"> <form class="form-horizontal" role="form" id="ownerPassForm">
<p> <p>
<%=l 'SET_OWNER_PASS_PERSISTENT' %> <%=l 'SET_OWNER_PASS' %>
<ul> <ul>
<li> <li>
<%= sprintf($self->l('A_STANDARD_ROOM_EXPIRES_AFTER_d'), int($config->{inactivityTimeout}/3600)) %> <%= sprintf($self->l('A_STANDARD_ROOM_EXPIRES_AFTER_d'), int($config->{inactivityTimeout}/3600)) %>
</li> </li>
<li> <li>
<%=l 'A_PERSISTENT_ROOM' %> <%=l 'A_RESERVED_ROOM' %>
<% if ($config->{persistentInactivityTimeout} > 0){ %> <% if ($config->{reservedInactivityTimeout} > 0){ %>
<%= sprintf($self->l('EXPIRE_AFTER_d'), int($config->{persistentInactivityTimeout}/(3600*24))) %> <%= sprintf($self->l('EXPIRE_AFTER_d'), int($config->{reservedInactivityTimeout}/(3600*24))) %>
<% } else{ %> <% } else{ %>
<%=l 'WILL NEVER_EXPIRE' %> <%=l 'WILL_NEVER_EXPIRE' %>
<% } %> <% } %>
</li> </li>
</ul> </ul>

Loading…
Cancel
Save