Move email invitation to the new API handler

master
Daniel Berteaud 10 years ago
parent 59aadfbbfb
commit 3a3603df1a
  1. 12
      lib/Vroom/Constants.pm
  2. 16
      public/js/vroom.js
  3. 1
      templates/default/js_common.html.ep
  4. 151
      vroom.pl

@ -4,7 +4,7 @@ use strict;
use warnings; use warnings;
use base 'Exporter'; use base 'Exporter';
our @EXPORT = qw/COMPONENTS MOH JS_STRINGS/; our @EXPORT = qw/COMPONENTS MOH JS_STRINGS API_ACTIONS/;
# Components used to generate the credits part # Components used to generate the credits part
use constant COMPONENTS => { use constant COMPONENTS => {
@ -152,5 +152,15 @@ use constant JS_STRINGS => qw(
ROOM_DATA_WIPED_BY_s ROOM_DATA_WIPED_BY_s
); );
# API actions
use constant API_ACTIONS => {
admin => {
list_rooms => 1
},
owner => {
invite_email => 1
},
participant => {}
};
1; 1;

@ -38,6 +38,9 @@ $.ajaxSetup({
url: rootUrl + 'jsapi', url: rootUrl + 'jsapi',
type: 'POST', type: 'POST',
dataType: 'json', dataType: 'json',
headers: {
'X-VROOM-API-Key': api_key
}
}); });
// Handle lang switch // Handle lang switch
@ -1573,11 +1576,16 @@ function initVroom(room) {
return; return;
} }
$.ajax({ $.ajax({
url: rootUrl + 'api',
data: { data: {
action: 'invite', req: JSON.stringify({
recipient: rcpt, action: 'invite_email',
message: message, param: {
room: roomName rcpt: rcpt,
message: message,
room: roomName
}
})
}, },
error: function(data) { error: function(data) {
$.notify(locale.ERROR_OCCURRED, 'error'); $.notify(locale.ERROR_OCCURRED, 'error');

@ -1,6 +1,7 @@
<script type="text/javascript"> <script type="text/javascript">
var rootUrl = '<%= $self->get_url('/'); %>'; var rootUrl = '<%= $self->get_url('/'); %>';
var currentLang = '<%= $self->languages %>'; var currentLang = '<%= $self->languages %>';
var api_key = '<%= ($self->session('key')) ? $self->session('key') : '' %>';
</script> </script>
<% foreach my $js (qw(jquery-1.11.1.min.js bootstrap.min.js notify-combined.min.js bootstrap-switch.min.js vroom.js)){ <% foreach my $js (qw(jquery-1.11.1.min.js bootstrap.min.js notify-combined.min.js bootstrap-switch.min.js vroom.js)){
%> %>

@ -17,6 +17,7 @@ use File::Basename;
use Etherpad::API; use Etherpad::API;
use Session::Token; use Session::Token;
use Config::Simple; use Config::Simple;
use Data::Dumper;
app->log->level('info'); app->log->level('info');
# Read conf file, and set default values # Read conf file, and set default values
@ -456,7 +457,7 @@ helper purge_api_keys => sub {
$self->app->log->debug('Removing expired API keys'); $self->app->log->debug('Removing expired API keys');
my $sth = eval { my $sth = eval {
$self->db->prepare('DELETE FROM `api_keys` $self->db->prepare('DELETE FROM `api_keys`
WHERE `not_after` > CONVERT_TZ(NOW(), @@session.time_zone, \'+00:00\')'); WHERE `not_after` < CONVERT_TZ(NOW(), @@session.time_zone, \'+00:00\')');
}; };
$sth->execute; $sth->execute;
return 1; return 1;
@ -869,7 +870,7 @@ helper get_key_by_token => sub {
$self->db->prepare('SELECT * $self->db->prepare('SELECT *
FROM `api_keys` FROM `api_keys`
WHERE `token`=? WHERE `token`=?
AND `not_after` < CONVERT_TZ(NOW(), @@session.time_zone, \'+00:00\') AND `not_after` > CONVERT_TZ(NOW(), @@session.time_zone, \'+00:00\')
LIMIT 1'); LIMIT 1');
}; };
$sth->execute($token); $sth->execute($token);
@ -892,10 +893,65 @@ helper associate_key_to_room => sub {
VALUES (?,?,?) VALUES (?,?,?)
ON DUPLICATE KEY UPDATE `role`=?'); ON DUPLICATE KEY UPDATE `role`=?');
}; };
$sth->execute($room->{id},$key->{id},$data->{role},$data->{role}); $sth->execute(
$room->{id},
$key->{id},
$data->{role},
$data->{role}
);
return 1; return 1;
}; };
# Check if a key can perform an action against a room
helper key_can_do_this => sub {
my $self = shift;
my (%data) = @_;
my $data = \%data;
if (!$data->{action}){
return 0;
}
my $key = $self->get_key_by_token($data->{token});
if (!$key){
$self->app->log->debug("Invalid API key");
return 0;
}
# API key is an admin one ?
if ($key->{admin}){
$self->app->log->debug("Admin API Key");
return 1;
}
# Global actions can only be performed by admin keys
if (!$key->{admin} && !$data->{param}->{room}){
$self->app->log->debug("Non admin API Key doesn't allow global actions");
return 0;
}
# Now, lookup the DB the role of this key for this room
my $sth = eval {
$self->db->prepare('SELECT role
FROM `room_keys`
LEFT JOIN `rooms` ON `room_keys`.`room_id`=`rooms`.`id`
WHERE `room_keys`.`key_id`=?
LIMIT 1');
};
$sth->execute($key->{id});
$sth->bind_columns(\$key->{role});
$sth->fetch;
my $actions = API_ACTIONS;
$self->app->log->debug("Key role: " . $key->{role} . " and action: " . $data->{action});
# If this key has owner privileges on this room, allow both owner and partitipant actions
if ($key->{role} eq 'owner' && ($actions->{owner}->{$data->{action}} || $actions->{participant}->{$data->{action}})){
return 1;
}
# If this key as simple partitipant priv in this room, only allow participant actions
elsif ($key->{role} eq 'partitipant' && $actions->{participant}->{$data->{action}}){
return 1;
}
# Else, deny
$self->app->log->debug("API Key " . $data->{key} . " cannot run action " . $data->{action} . " on room " . $data->{param}->{room});
return 0;
};
# Route / to the index page # Route / to the index page
get '/' => sub { get '/' => sub {
my $self = shift; my $self = shift;
@ -1129,8 +1185,6 @@ any [qw(GET POST)] => '/password/(:room)' => sub {
# API requests handler # API requests handler
any '/api' => sub { any '/api' => sub {
my $self = shift; my $self = shift;
my @anon_actions = qw(switch_lang);
my @admin_actions = qw(list_rooms);
$self->purge_api_keys; $self->purge_api_keys;
my $token = $self->req->headers->header('X-VROOM-API-Key'); my $token = $self->req->headers->header('X-VROOM-API-Key');
my $json = Mojo::JSON->new; my $json = Mojo::JSON->new;
@ -1164,8 +1218,13 @@ any '/api' => sub {
); );
} }
# Ok, now, lets check the API key is valid # Now, lets check the key can do the requested action
if (!$token){ my $res = $self->key_can_do_this(
token => $token,
action => $req->{action},
param => $req->{param}
);
if (!$res){
return $self->render( return $self->render(
json => { json => {
status => 'error', status => 'error',
@ -1174,6 +1233,47 @@ any '/api' => sub {
status => '403' status => '403'
); );
} }
# Ok, now, we don't have to bother with authorization anymore
if ($req->{action} eq 'invite_email'){
my $room = $self->get_room_by_name($req->{param}->{room});
if (!$req->{param}->{rcpt} || $req->{param}->{rcpt}!~ m/\S+@\S+\.\S+$/){
return $self->render(
json => {
status => 'error',
msg => 'ERROR_MAIL_INVALID'
}
);
}
my $token = $self->add_invitation(
$req->{param}->{room},
$req->{param}->{rcpt}
);
my $sent = $self->mail(
to => $req->{param}->{rcpt},
subject => $self->l("EMAIL_INVITATION"),
data => $self->render_mail('invite',
room => $req->{param}->{room},
message => $req->{param}->{message},
token => $token,
joinPass => ($room->{join_password}) ? 'yes' : 'no'
)
);
if ($token && $sent){
$self->app->log->info("Email invitation to join room " . $req->{param}->{room} . " sent to " . $req->{param}->{rcpt});
return $self->render(
json => {
status => 'success',
msg => sprintf($self->l('INVITE_SENT_TO_s'), $req->{param}->{rcpt})
}
);
}
return $self->render(
json => {
status => 'error',
msg => 'ERROR_OCCURRED'
}
);
}
}; };
# Catch all route: if nothing else match, it's the name of a room # Catch all route: if nothing else match, it's the name of a room
@ -1314,43 +1414,6 @@ post '/*jsapi' => { jsapi => [qw(jsapi admin/jsapi)] } => sub {
); );
} }
# Handle email invitation
if ($action eq 'invite'){
my $rcpt = $self->param('recipient');
my $message = $self->param('message');
my $status = 'error';
my $msg = $self->l('ERROR_OCCURRED');
if ($prefix ne 'admin' && $self->session($room)->{role} ne 'owner'){
$msg = 'NOT_ALLOWED';
}
elsif ($rcpt !~ m/\S+@\S+\.\S+$/){
$msg = $self->l('ERROR_MAIL_INVALID');
}
else{
my $token = $self->add_invitation($room,$rcpt);
my $sent = $self->mail(
to => $rcpt,
subject => $self->l("EMAIL_INVITATION"),
data => $self->render_mail('invite',
room => $room,
message => $message,
token => $token,
joinPass => ($data->{join_password}) ? 'yes' : 'no'
)
);
if ($token && $sent){
$self->app->log->info($self->session('name') . " sent an invitation for room $room to $rcpt");
$status = 'success';
$msg = sprintf($self->l('INVITE_SENT_TO_s'), $rcpt);
}
}
$self->render(
json => {
msg => $msg,
status => $status
}
);
}
# Handle room lock/unlock # Handle room lock/unlock
if ($action =~ m/(un)?lock/){ if ($action =~ m/(un)?lock/){
my ($lock,$success); my ($lock,$success);

Loading…
Cancel
Save