You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ngcp-panel/lib/NGCP/Panel/Controller/Subscriber.pm

706 lines
26 KiB

package NGCP::Panel::Controller::Subscriber;
use Sipwise::Base;
use namespace::sweep;
BEGIN { extends 'Catalyst::Controller'; }
use NGCP::Panel::Utils::Contract;
use NGCP::Panel::Form::Subscriber;
use NGCP::Panel::Form::SubscriberCFSimple;
use NGCP::Panel::Form::SubscriberCFTSimple;
use NGCP::Panel::Form::SubscriberCFAdvanced;
#use NGCP::Panel::Form::SubscriberCFTAdvanced;
use UUID;
use Data::Printer;
=head1 NAME
NGCP::Panel::Controller::Subscriber - Catalyst Controller
=head1 DESCRIPTION
Catalyst Controller.
=head1 METHODS
=cut
sub auto :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
my ($self, $c) = @_;
$c->log->debug(__PACKAGE__ . '::auto');
return 1;
}
sub sub_list :Chained('/') :PathPart('subscriber') :CaptureArgs(0) {
my ($self, $c) = @_;
$c->stash(
template => 'subscriber/list.tt',
);
}
sub root :Chained('sub_list') :PathPart('') :Args(0) {
my ($self, $c) = @_;
}
sub create_list :Chained('sub_list') :PathPart('create') :Args(0) {
my ($self, $c) = @_;
my $form = NGCP::Panel::Form::Subscriber->new;
$form->process(
posted => ($c->request->method eq 'POST'),
params => $c->request->params,
action => $c->uri_for('/subscriber/create'),
);
return if NGCP::Panel::Utils::check_form_buttons(
c => $c,
form => $form,
fields => [qw/domain.create/],
back_uri => $c->uri_for('/subscriber/create'),
);
if($form->validated) {
my $schema = $c->model('DB');
try {
$schema->txn_do(sub {
my ($uuid_bin, $uuid_string);
UUID::generate($uuid_bin);
UUID::unparse($uuid_bin, $uuid_string);
# TODO: check if we find a reseller and contract and domains
my $reseller = $schema->resultset('resellers')
->find($c->request->params->{'reseller.id'});
my $contract = $schema->resultset('contracts')
->find($c->request->params->{'contract.id'});
my $prov_domain = $schema->resultset('voip_domains')
->find($c->request->params->{'domain.id'});
my $billing_domain = $schema->resultset('domains')
->find({domain => $prov_domain->domain});
my $number;
if(defined $c->request->params->{'e164.cc'} &&
$c->request->params->{'e164.cc'} ne '') {
$number = $reseller->voip_numbers->create({
cc => $c->request->params->{'e164.cc'},
ac => $c->request->params->{'e164.ac'} || '',
sn => $c->request->params->{'e164.sn'},
status => 'active',
});
}
my $billing_subscriber = $contract->voip_subscribers->create({
uuid => $uuid_string,
username => $c->request->params->{username},
domain_id => $billing_domain->id,
status => $c->request->params->{status},
primary_number_id => defined $number ? $number->id : undef,
});
if(defined $number) {
$number->update({ subscriber_id => $billing_subscriber->id });
}
my $prov_subscriber = $schema->resultset('provisioning_voip_subscribers')->create({
uuid => $uuid_string,
username => $c->request->params->{username},
password => $c->request->params->{password},
webusername => $c->request->params->{webusername} || $c->request->params->{username},
webpassword => $c->request->params->{webpassword},
admin => $c->request->params->{administrative} || 0,
account_id => $contract->id,
domain_id => $prov_domain->id,
});
my $voip_preferences = $schema->resultset('voip_preferences')->search({
'usr_pref' => 1,
});
$voip_preferences->find({ 'attribute' => 'account_id' })
->voip_usr_preferences->create({
'subscriber_id' => $prov_subscriber->id,
'value' => $prov_subscriber->contract->id,
});
$voip_preferences->find({ 'attribute' => 'ac' })
->voip_usr_preferences->create({
'subscriber_id' => $prov_subscriber->id,
'value' => $c->request->params->{'e164.ac'},
}) if (defined $c->request->params->{'e164.ac'} &&
length($c->request->params->{'e164.ac'}) > 0);
if(defined $c->request->params->{'e164.cc'} &&
length($c->request->params->{'e164.cc'}) > 0) {
$voip_preferences->find({ 'attribute' => 'cc' })
->voip_usr_preferences->create({
'subscriber_id' => $prov_subscriber->id,
'value' => $c->request->params->{'e164.cc'},
});
my $cli = $c->request->params->{'e164.cc'} .
(defined $c->request->params->{'e164.ac'} &&
length($c->request->params->{'e164.ac'}) > 0 ?
$c->request->params->{'e164.ac'} : ''
) .
$c->request->params->{'e164.sn'};
$voip_preferences->find({ 'attribute' => 'cli' })
->voip_usr_preferences->create({
'subscriber_id' => $prov_subscriber->id,
'value' => $cli,
});
}
});
$c->flash(messages => [{type => 'success', text => 'Subscriber successfully created!'}]);
$c->response->redirect($c->uri_for('/subscriber'));
return;
} catch($e) {
$c->log->error("Failed to create subscriber: $e");
$c->flash(messages => [{type => 'error', text => 'Creating subscriber failed!'}]);
$c->response->redirect($c->uri_for('/subscriber'));
return;
}
}
$c->stash(close_target => $c->uri_for());
$c->stash(create_flag => 1);
$c->stash(form => $form)
}
sub base :Chained('/subscriber/sub_list') :PathPart('') :CaptureArgs(1) {
my ($self, $c, $subscriber_id) = @_;
unless($subscriber_id && $subscriber_id->is_integer) {
$c->flash(messages => [{type => 'error', text => 'Invalid subscriber id detected!'}]);
$c->response->redirect($c->uri_for());
return;
}
my $res = $c->model('DB')->resultset('voip_subscribers')->find({ id => $subscriber_id });
unless(defined $res) {
$c->flash(messages => [{type => 'error', text => 'Subscriber does not exist!'}]);
$c->response->redirect($c->uri_for('/subscriber'));
$c->detach;
}
$c->stash(subscriber => $res);
}
sub ajax :Chained('sub_list') :PathPart('ajax') :Args(0) {
my ($self, $c) = @_;
my $dispatch_to = '_ajax_resultset_' . $c->user->auth_realm;
my $resultset = $self->$dispatch_to($c);
$c->forward( "/ajax_process_resultset", [$resultset,
["id", "username", "domain_id", "contract_id", "status",],
["username", "domain_id", "contract_id", "status",]]);
$c->detach( $c->view("JSON") );
}
sub _ajax_resultset_admin {
my ($self, $c) = @_;
return $c->model('DB')->resultset('voip_subscribers');
}
sub _ajax_resultset_reseller {
my ($self, $c) = @_;
# TODO: filter for reseller
return $c->model('DB')->resultset('voip_subscribers');
}
sub terminate :Chained('base') :PathPart('terminate') :Args(0) {
my ($self, $c) = @_;
my $subscriber = $c->stash->{subscriber};
my $schema = $c->model('DB');
try {
$schema->txn_do(sub {
use Data::Printer;
p $subscriber;
$subscriber->provisioning_voip_subscriber->delete;
$subscriber->update({ status => 'terminated' });
});
$c->flash(messages => [{type => 'success', text => 'Successfully terminated subscriber'}]);
$c->response->redirect($c->uri_for());
return;
} catch($e) {
$c->log->error("Failed to terminate subscriber: $e");
$c->flash(messages => [{type => 'error', text => 'Failed to terminate subscriber'}]);
$c->response->redirect($c->uri_for());
return;
}
}
sub preferences :Chained('base') :PathPart('preferences') :Args(0) {
my ($self, $c) = @_;
$self->load_preference_list($c);
$c->stash(template => 'subscriber/preferences.tt');
my $prov_subscriber = $c->stash->{subscriber}->provisioning_voip_subscriber;
my $cfs = {};
my $mappings = {};
for my $type(qw/cfu cfna cft cfb/) {
$mappings->{$type} = $prov_subscriber->voip_cf_mappings
->find({ type => $type });
if(defined $mappings->{$type}) {
$cfs->{$type} = [ $mappings->{$type}
->destination_set
->voip_cf_destinations->search({},
{ order_by => { -asc => 'priority' }}
)->all ];
}
}
$c->stash(cf_mappings => $mappings);
$c->stash(cf_destinations => $cfs);
my $ringtimeout_preference = $c->model('DB')->resultset('voip_preferences')->search({
attribute => 'ringtimeout', 'usr_pref' => 1,
})->first->voip_usr_preferences->find({
subscriber_id => $prov_subscriber->id,
});
$c->stash(cf_ringtimeout => $ringtimeout_preference ? $ringtimeout_preference->value : undef);
}
sub preferences_base :Chained('base') :PathPart('preferences') :CaptureArgs(1) {
my ($self, $c, $pref_id) = @_;
$self->load_preference_list($c);
$c->stash->{preference_meta} = $c->model('DB')
->resultset('voip_preferences')
->single({id => $pref_id});
$c->stash->{preference} = $c->model('DB')
->resultset('voip_usr_preferences')
->search({
attribute_id => $pref_id,
subscriber_id => $c->stash->{subscriber}->provisioning_voip_subscriber->id
});
my @values = $c->stash->{preference}->get_column("value")->all;
$c->stash->{preference_values} = \@values;
$c->stash(template => 'subscriber/preferences.tt');
}
sub preferences_edit :Chained('preferences_base') :PathPart('edit') :Args(0) {
my ($self, $c) = @_;
$c->stash(edit_preference => 1);
my @enums = $c->stash->{preference_meta}
->voip_preferences_enums
->search({usr_pref => 1})
->all;
my $pref_rs = $c->model('DB')
->resultset('voip_usr_preferences')
->search({
subscriber_id => $c->stash->{subscriber}->provisioning_voip_subscriber->id
});
NGCP::Panel::Utils::create_preference_form( c => $c,
pref_rs => $pref_rs,
enums => \@enums,
base_uri => $c->uri_for_action('/subscriber/preferences', [$c->req->captures->[0]]),
edit_uri => $c->uri_for_action('/subscriber/preferences_edit', $c->req->captures),
);
}
sub preferences_callforward :Chained('base') :PathPart('preferences/callforward') :Args(1) {
my ($self, $c, $cf_type) = @_;
say ">>>>>>>>>>>>>>>>>>>>>> preferences_callforward";
my $cf_desc;
given($cf_type) {
when("cfu") { $cf_desc = "Unconditional" }
when("cfb") { $cf_desc = "Busy" }
when("cft") { $cf_desc = "Timeout" }
when("cfna") { $cf_desc = "Unavailable" }
default {
$c->log->error("Invalid call-forward type '$cf_type'");
$c->flash(messages => [{type => 'error', text => 'Invalid Call Forward type'}]);
$c->response->redirect($c->uri_for_action('/subscriber/preferences', [$c->req->captures->[0]]));
return;
}
}
my $posted = ($c->request->method eq 'POST');
my $voip_preferences = $c->model('DB')->resultset('voip_preferences')->search({
'usr_pref' => 1,
});
my $cf_preference = $voip_preferences->find({ 'attribute' => $cf_type })
->voip_usr_preferences;
my $ringtimeout_preference = $voip_preferences->find({ 'attribute' => 'ringtimeout' })
->voip_usr_preferences;
my $billing_subscriber = $c->stash->{subscriber};
my $prov_subscriber = $billing_subscriber->provisioning_voip_subscriber;
my $cf_mapping = $prov_subscriber->voip_cf_mappings->find({ type => $cf_type });
my $destination;
if($cf_mapping &&
$cf_mapping->destination_set &&
$cf_mapping->destination_set->voip_cf_destinations->first) {
$destination = $cf_mapping->destination_set->voip_cf_destinations->first;
}
my $params = {};
if($destination) {
$params->{destination} = $destination->destination;
if($cf_type eq 'cft') {
my $rt = $ringtimeout_preference->find({ subscriber_id => $prov_subscriber->id });
if($rt) {
$params->{ringtimeout} = $rt->value;
} else {
$params->{ringtimeout} = 15;
}
}
}
if($posted) {
$params = $c->request->params;
if(!defined($c->request->params->{submitid})) {
if($params->{destination} !~ /\@/) {
$params->{destination} .= '@'.$billing_subscriber->domain->domain;
}
if($params->{destination} !~ /^sip:/) {
$params->{destination} = 'sip:' . $params->{destination};
}
}
}
my $cf_form;
if($cf_type eq "cft") {
$cf_form = NGCP::Panel::Form::SubscriberCFTSimple->new;
} else {
$cf_form = NGCP::Panel::Form::SubscriberCFSimple->new;
}
$cf_form->process(
params => $params,
);
# TODO: if more than one entry in $cf_mapping->voip_cf_destination_set->voip_cf_destinations,
# show advanced mode and list them all; same for time sets
return if NGCP::Panel::Utils::check_form_buttons(
c => $c, form => $cf_form,
fields => {
'cf_actions.advanced' =>
$c->uri_for_action('/subscriber/preferences_callforward_advanced',
[$c->req->captures->[0]], $cf_type, 'advanced'
),
},
back_uri => $c->uri_for($c->action, $c->req->captures)
);
if($posted && $cf_form->validated) {
try {
$c->model('DB')->schema->txn_do( sub {
my $dest_set = $c->model('DB')->resultset('voip_cf_destination_sets')->find({
subscriber_id => $prov_subscriber->id,
name => 'quickset_'.$cf_type,
});
unless($dest_set) {
$dest_set = $c->model('DB')->resultset('voip_cf_destination_sets')->create({
name => 'quickset_'.$cf_type,
subscriber_id => $prov_subscriber->id,
});
} else {
my @all = $dest_set->voip_cf_destinations->all;
foreach my $dest(@all) {
$dest->delete;
}
}
my $dest = $dest_set->voip_cf_destinations->create({
priority => 1,
timeout => 300,
destination => $c->request->params->{destination},
});
unless(defined $cf_mapping) {
$cf_mapping = $prov_subscriber->voip_cf_mappings->create({
type => $cf_type,
# subscriber_id => $prov_subscriber->id,
destination_set_id => $dest_set->id,
time_set_id => undef, #$time_set_id,
});
}
my $cf_preference_row = $cf_preference->find({
subscriber_id => $prov_subscriber->id
});
if($cf_preference_row) {
$cf_preference_row->update({ value => $cf_mapping->id });
} else {
$cf_preference->create({
subscriber_id => $prov_subscriber->id,
value => $cf_mapping->id,
});
}
if($cf_type eq 'cft') {
my $ringtimeout_preference_row = $ringtimeout_preference->find({
subscriber_id => $prov_subscriber->id
});
if($ringtimeout_preference_row) {
$ringtimeout_preference_row->update({
value => $c->request->params->{ringtimeout}
});
} else {
$ringtimeout_preference->create({
subscriber_id => $prov_subscriber->id,
value => $c->request->params->{ringtimeout},
});
}
}
});
} catch($e) {
$c->log->error("failed to save call-forward: $e");
$c->flash(messages => [{type => 'error', text => 'Failed to save Call Forward'}]);
$c->response->redirect($c->uri_for_action('/subscriber/preferences', [$c->req->captures->[0]]));
return;
}
$c->flash(messages => [{type => 'success', text => 'Successfully saved Call Forward'}]);
$c->response->redirect($c->uri_for_action('/subscriber/preferences', [$c->req->captures->[0]]));
return;
}
$self->load_preference_list($c);
$c->stash(template => 'subscriber/preferences.tt');
$c->stash(
edit_cf_flag => 1,
cf_description => $cf_desc,
cf_form => $cf_form,
);
}
sub preferences_callforward_advanced :Chained('base') :PathPart('preferences/callforward') :Args(2) {
my ($self, $c, $cf_type, $advanced) = @_;
say ">>>>>>>>>>>>>>>>>>>>>> preferences_callforward_advanced";
if(defined $advanced && $advanced eq 'advanced') {
$advanced = 1;
} else {
$advanced = 0;
}
my $cf_desc;
given($cf_type) {
when("cfu") { $cf_desc = "Unconditional" }
when("cfb") { $cf_desc = "Busy" }
when("cft") { $cf_desc = "Timeout" }
when("cfna") { $cf_desc = "Unavailable" }
default {
$c->log->error("Invalid call-forward type '$cf_type'");
$c->flash(messages => [{type => 'error', text => 'Invalid Call Forward type'}]);
$c->response->redirect($c->uri_for_action('/subscriber/preferences', [$c->req->captures->[0]]));
return;
}
}
my $billing_subscriber = $c->stash->{subscriber};
my $prov_subscriber = $billing_subscriber->provisioning_voip_subscriber;
my $cf_mapping = $prov_subscriber->voip_cf_mappings->find({ type => $cf_type });
if($cf_mapping) {
$c->stash->{cf_active_destination_set} = $cf_mapping->destination_set
if($cf_mapping->destination_set);
$c->stash->{cf_destination_sets} = $prov_subscriber->voip_cf_destination_sets;
$c->stash->{cf_active_time_set} = $cf_mapping->time_set
if($cf_mapping->time_set);
$c->stash->{cf_time_sets} = $prov_subscriber->voip_cf_time_sets;
}
my $destination;
if($cf_mapping &&
$cf_mapping->destination_set &&
$cf_mapping->destination_set->voip_cf_destinations->first) {
$destination = $cf_mapping->destination_set->voip_cf_destinations->first;
}
my $posted = ($c->request->method eq 'POST');
my $cf_form;
# my $params = {};
# if($cf_type eq "cft") {
# $cf_form = NGCP::Panel::Form::SubscriberCFTAdvanced->new;
# } else {
$cf_form = NGCP::Panel::Form::SubscriberCFAdvanced->new(ctx => $c);
# }
$cf_form->process(
params => $posted ? $c->request->params : {}
);
say ">>>>>>>>>>>>>>>>>>>>>>>> check_form_buttons";
return if NGCP::Panel::Utils::check_form_buttons(
c => $c, form => $cf_form,
fields => {
'cf_actions.simple' =>
$c->uri_for_action('/subscriber/preferences_callforward',
[$c->req->captures->[0], $cf_type],
),
},
back_uri => $c->uri_for($c->action, $c->req->captures)
);
say ">>>>>>>>>>>>>>>>>>>>>>>> after check_form_buttons";
=pod
if($posted && $cf_form->validated) {
try {
$c->model('DB')->schema->txn_do( sub {
my $dest_set = $c->model('DB')->resultset('voip_cf_destination_sets')->find({
subscriber_id => $prov_subscriber->id,
name => 'quickset_'.$cf_type,
});
unless($dest_set) {
$dest_set = $c->model('DB')->resultset('voip_cf_destination_sets')->create({
name => 'quickset_'.$cf_type,
subscriber_id => $prov_subscriber->id,
});
} else {
my @all = $dest_set->voip_cf_destinations->all;
foreach my $dest(@all) {
$dest->delete;
}
}
my $dest = $dest_set->voip_cf_destinations->create({
priority => 1,
timeout => 300,
destination => $c->request->params->{destination},
});
unless(defined $cf_mapping) {
$cf_mapping = $prov_subscriber->voip_cf_mappings->create({
type => $cf_type,
# subscriber_id => $prov_subscriber->id,
destination_set_id => $dest_set->id,
time_set_id => undef, #$time_set_id,
});
}
my $cf_preference_row = $cf_preference->find({
subscriber_id => $prov_subscriber->id
});
if($cf_preference_row) {
$cf_preference_row->update({ value => $cf_mapping->id });
} else {
$cf_preference->create({
subscriber_id => $prov_subscriber->id,
value => $cf_mapping->id,
});
}
if($cf_type eq 'cft') {
my $ringtimeout_preference_row = $ringtimeout_preference->find({
subscriber_id => $prov_subscriber->id
});
if($ringtimeout_preference_row) {
$ringtimeout_preference_row->update({
value => $c->request->params->{ringtimeout}
});
} else {
$ringtimeout_preference->create({
subscriber_id => $prov_subscriber->id,
value => $c->request->params->{ringtimeout},
});
}
}
});
} catch($e) {
$c->log->error("failed to save call-forward: $e");
$c->flash(messages => [{type => 'error', text => 'Failed to save Call Forward'}]);
$c->response->redirect($c->uri_for_action('/subscriber/preferences', [$c->req->captures->[0]]));
return;
}
$c->flash(messages => [{type => 'success', text => 'Successfully saved Call Forward'}]);
$c->response->redirect($c->uri_for_action('/subscriber/preferences', [$c->req->captures->[0]]));
return;
}
=cut
$self->load_preference_list($c);
$c->stash(template => 'subscriber/preferences.tt');
$c->stash(
edit_cf_flag => 1,
cf_description => $cf_desc,
cf_form => $cf_form,
);
}
sub preferences_callforward_delete :Chained('base') :PathPart('preferences/callforward/delete') :Args(1) {
my ($self, $c, $cfmap_id) = @_;
try {
$c->model('DB')->resultset('voip_cf_mappings')->find($cfmap_id)->delete;
$c->flash(messages => [{type => 'success', text => 'Successfully deleted Call Forward'}]);
} catch($e) {
$c->log->error("failed to delete call forward mapping: $e");
$c->flash(messages => [{type => 'error', text => 'Failed to deleted Call Forward'}]);
}
$c->response->redirect($c->uri_for_action('/subscriber/preferences', [$c->req->captures->[0]]));
}
sub load_preference_list :Private {
my ($self, $c) = @_;
my $usr_pref_values = $c->model('DB')
->resultset('voip_preferences')
->search({
'subscriber.id' => $c->stash->{subscriber}->provisioning_voip_subscriber->id
},{
prefetch => {'voip_usr_preferences' => 'subscriber'},
});
my %pref_values;
foreach my $value($usr_pref_values->all) {
$pref_values{$value->attribute} = [
map {$_->value} $value->voip_usr_preferences->all
];
}
my $rewrite_rule_sets_rs = $c->model('DB')
->resultset('voip_rewrite_rule_sets');
$c->stash(rwr_sets_rs => $rewrite_rule_sets_rs,
rwr_sets => [$rewrite_rule_sets_rs->all]);
my $ncos_levels_rs = $c->model('DB')
->resultset('ncos_levels');
$c->stash(ncos_levels_rs => $ncos_levels_rs,
ncos_levels => [$ncos_levels_rs->all]);
my $sound_sets_rs = $c->model('DB')
->resultset('voip_sound_sets');
$c->stash(sound_sets_rs => $sound_sets_rs,
sound_sets => [$sound_sets_rs->all]);
NGCP::Panel::Utils::load_preference_list( c => $c,
pref_values => \%pref_values,
usr_pref => 1,
);
}
sub master :Chained('/') :PathPart('subscriber') :Args(1) {
my ($self, $c, $subscriber_id) = @_;
$c->stash(
template => 'subscriber/master.tt',
);
}
=head1 AUTHOR
Andreas Granig,,,
=head1 LICENSE
This library is free software. You can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
__PACKAGE__->meta->make_immutable;
1;
# vim: set tabstop=4 expandtab: