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.
2122 lines
78 KiB
2122 lines
78 KiB
package NGCP::Panel::Controller::Device;
|
|
use NGCP::Panel::Utils::Generic qw(:all);
|
|
use Sipwise::Base;
|
|
|
|
use Template;
|
|
use Crypt::Rijndael;
|
|
use Digest::MD5 qw/md5_hex/;
|
|
use Storable qw/freeze/;
|
|
use JSON qw(decode_json encode_json);
|
|
use NGCP::Panel::Form;
|
|
use NGCP::Panel::Utils::Navigation;
|
|
use NGCP::Panel::Utils::DeviceBootstrap;
|
|
use NGCP::Panel::Utils::Device;
|
|
use NGCP::Panel::Utils::DeviceFirmware;
|
|
use NGCP::Panel::Utils::DateTime;
|
|
use NGCP::Panel::Utils::Preferences;
|
|
use DateTime::Format::HTTP;
|
|
|
|
use parent 'Catalyst::Controller';
|
|
|
|
sub auto :Private {
|
|
my ($self, $c) = @_;
|
|
$c->log->debug(__PACKAGE__ . '::auto');
|
|
return 1;
|
|
}
|
|
|
|
sub base :Chained('/') :PathPart('device') :CaptureArgs(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
NGCP::Panel::Utils::Navigation::check_redirect_chain(c => $c);
|
|
|
|
# TODO: move out fw/profile/config fetching to separate func to not
|
|
# load it for subscriber access?
|
|
my $reseller_id;
|
|
if($c->user->roles eq 'reseller') {
|
|
$reseller_id = $c->user->reseller_id;
|
|
} elsif($c->user->roles eq 'subscriber' || $c->user->roles eq 'subscriberadmin') {
|
|
$reseller_id = $c->user->voip_subscriber->contract->contact->reseller_id;
|
|
}
|
|
|
|
my $devmod_rs = $c->model('DB')->resultset('autoprov_devices')->search_rs(undef,{
|
|
'columns' => [qw/id reseller_id type vendor model front_image_type mac_image_type front_thumbnail_type num_lines bootstrap_method bootstrap_uri extensions_num/,
|
|
{
|
|
mac_image_exists => \'mac_image is not null',
|
|
front_image_exists => \'front_image is not null',
|
|
front_thumbnail_exists => \'front_thumbnail is not null',
|
|
}
|
|
],
|
|
});
|
|
|
|
$reseller_id and $devmod_rs = $devmod_rs->search({ reseller_id => $reseller_id });
|
|
$c->stash->{devmod_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [
|
|
{ name => 'id', search => 1, title => $c->loc('#') },
|
|
{ name => 'type', search => 1, title => $c->loc('Type') },
|
|
{ name => 'reseller.name', search => 1, title => $c->loc('Reseller') },
|
|
{ name => 'vendor', search => 1, title => $c->loc('Vendor') },
|
|
{ name => 'model', search => 1, title => $c->loc('Model') },
|
|
]);
|
|
|
|
my $devfw_rs = $c->model('DB')->resultset('autoprov_firmwares')->search_rs(undef,{'columns' => [qw/id device_id version filename tag/],
|
|
});
|
|
$reseller_id and $devfw_rs = $devfw_rs->search({
|
|
'device.reseller_id' => $reseller_id,
|
|
},{
|
|
join => 'device',
|
|
});
|
|
$c->stash->{devfw_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [
|
|
{ name => 'id', search => 1, title => $c->loc('#') },
|
|
{ name => 'device.reseller.name', search => 1, title => $c->loc('Reseller') },
|
|
{ name => 'device.vendor', search => 1, title => $c->loc('Device Vendor') },
|
|
{ name => 'device.model', search => 1, title => $c->loc('Device Model') },
|
|
{ name => 'filename', search => 1, title => $c->loc('Firmware File') },
|
|
{ name => 'version', search => 1, title => $c->loc('Version') },
|
|
{ name => 'tag', search => 1, title => $c->loc('Firmware Tag') },
|
|
]);
|
|
|
|
my $devconf_rs = $c->model('DB')->resultset('autoprov_configs')->search_rs(undef,{'columns' => [qw/id device_id version content_type/],
|
|
});
|
|
$reseller_id and $devconf_rs = $devconf_rs->search({
|
|
'device.reseller_id' => $reseller_id,
|
|
}, {
|
|
join => 'device',
|
|
});
|
|
$c->stash->{devconf_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [
|
|
{ name => 'id', search => 1, title => $c->loc('#') },
|
|
{ name => 'device.reseller.name', search => 1, title => $c->loc('Reseller') },
|
|
{ name => 'device.vendor', search => 1, title => $c->loc('Device Vendor') },
|
|
{ name => 'device.model', search => 1, title => $c->loc('Device Model') },
|
|
{ name => 'version', search => 1, title => $c->loc('Version') },
|
|
]);
|
|
|
|
my $devprof_rs = $c->model('DB')->resultset('autoprov_profiles');
|
|
$reseller_id and $devprof_rs = $devprof_rs->search({
|
|
'device.reseller_id' => $reseller_id,
|
|
}, {
|
|
join => { 'config' => 'device' },
|
|
});
|
|
$c->stash->{devprof_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [
|
|
{ name => 'id', search => 1, title => $c->loc('#') },
|
|
{ name => 'config.device.reseller.name', search => 1, title => $c->loc('Reseller') },
|
|
{ name => 'name', search => 1, title => $c->loc('Name') },
|
|
{ name => 'config.device.vendor', search => 1, title => $c->loc('Device Vendor') },
|
|
{ name => 'config.device.model', search => 1, title => $c->loc('Device Model') },
|
|
# { name => 'firmware.filename', search => 1, title => $c->loc('Firmware File') },
|
|
{ name => 'config.version', search => 1, title => $c->loc('Configuration Version') },
|
|
]);
|
|
|
|
my $fielddev_rs = $c->model('DB')->resultset('autoprov_field_devices');
|
|
$reseller_id and $fielddev_rs = $fielddev_rs->search({
|
|
'device.reseller_id' => $reseller_id,
|
|
},{
|
|
join => { 'profile' => { 'config' => 'device' } },
|
|
});
|
|
$c->stash->{fielddev_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [
|
|
{ name => 'id', search => 1, title => $c->loc('#') },
|
|
{ name => 'identifier', search => 1, title => $c->loc('MAC Address / Identifier') },
|
|
{ name => 'profile.name', search => 1, title => $c->loc('Profile Name') },
|
|
{ name => 'contract.id', search => 1, title => $c->loc('Customer #') },
|
|
{ name => 'contract.contact.email', search => 1, title => $c->loc('Customer Email') },
|
|
]);
|
|
|
|
my $extensions_rs = $c->model('DB')->resultset('autoprov_devices')->search_rs({
|
|
'type' => 'extension',
|
|
});
|
|
$reseller_id and $extensions_rs = $extensions_rs->search({ reseller_id => $reseller_id });
|
|
|
|
$c->stash->{fielddev_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [
|
|
{ name => 'id', search => 1, title => $c->loc('#') },
|
|
{ name => 'identifier', search => 1, title => $c->loc('MAC Address / Identifier') },
|
|
{ name => 'profile.name', search => 1, title => $c->loc('Profile Name') },
|
|
{ name => 'contract.id', search => 1, title => $c->loc('Customer #') },
|
|
{ name => 'contract.contact.email', search => 1, title => $c->loc('Customer Email') },
|
|
]);
|
|
|
|
$c->stash(
|
|
devmod_rs => $devmod_rs,
|
|
devfw_rs => $devfw_rs,
|
|
devconf_rs => $devconf_rs,
|
|
devprof_rs => $devprof_rs,
|
|
fielddev_rs => $fielddev_rs,
|
|
extensions_rs => $extensions_rs,
|
|
reseller_id => $reseller_id,
|
|
template => 'device/list.tt',
|
|
);
|
|
}
|
|
|
|
sub root :Chained('base') :PathPart('') :Args(0) :Does(License) :RequiresLicense('pbx') :RequiresLicense('device_provisioning') :LicenseDetachTo('/denied_page') :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
|
my ($self, $c) = @_;
|
|
}
|
|
|
|
sub devmod_ajax :Chained('base') :PathPart('model/ajax') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $resultset = $c->stash->{devmod_rs};
|
|
NGCP::Panel::Utils::Datatables::process($c, $resultset, $c->stash->{devmod_dt_columns},
|
|
sub {
|
|
my ($result) = @_;
|
|
my %data = (
|
|
mac_image_exists => $result->get_column('mac_image_exists'),
|
|
front_image_exists => $result->get_column('front_image_exists'),
|
|
front_thumbnail_exists => $result->get_column('front_thumbnail_exists'),
|
|
);
|
|
return %data
|
|
},
|
|
);
|
|
$c->detach( $c->view("JSON") );
|
|
}
|
|
|
|
sub extensionmodel_ajax :Chained('base') :PathPart('extensionmodel/ajax') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $resultset = $c->stash->{devmod_rs}->search_rs({
|
|
'me.type' => 'extension',
|
|
});
|
|
NGCP::Panel::Utils::Datatables::process($c, $resultset, $c->stash->{devmod_dt_columns},
|
|
sub {
|
|
my ($result) = @_;
|
|
my %data = (
|
|
mac_image_exists => $result->get_column('mac_image_exists'),
|
|
front_image_exists => $result->get_column('front_image_exists'),
|
|
front_thumbnail_exists => $result->get_column('front_thumbnail_exists'),
|
|
);
|
|
return %data
|
|
},
|
|
);
|
|
$c->detach( $c->view("JSON") );
|
|
}
|
|
|
|
sub devmod_create :Chained('base') :PathPart('model/create') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $posted = ($c->request->method eq 'POST');
|
|
my $form;
|
|
if($c->user->is_superuser) {
|
|
$form = NGCP::Panel::Form::get("NGCP::Panel::Form::Device::ModelAdmin", $c);
|
|
} else {
|
|
$form = NGCP::Panel::Form::get("NGCP::Panel::Form::Device::Model", $c);
|
|
}
|
|
|
|
my $params = {};
|
|
$params = merge($params, $c->session->{created_objects});
|
|
if($posted) {
|
|
$c->req->params->{front_image} = $c->req->upload('front_image');
|
|
$c->req->params->{mac_image} = $c->req->upload('mac_image');
|
|
$c->req->params->{front_thumbnail} = $c->req->upload('front_thumbnail');
|
|
}
|
|
$form->process(
|
|
posted => $posted,
|
|
params => $c->request->params,
|
|
item => $params
|
|
);
|
|
NGCP::Panel::Utils::Navigation::check_form_buttons(
|
|
c => $c,
|
|
form => $form,
|
|
fields => {
|
|
'reseller.create' => $c->uri_for('/reseller/create'),
|
|
},
|
|
back_uri => $c->req->uri,
|
|
);
|
|
|
|
if($posted && $form->validated) {
|
|
try {
|
|
my $schema = $c->model('DB');
|
|
$schema->txn_do(sub {
|
|
if($c->user->is_superuser) {
|
|
$form->values->{reseller_id} = $form->values->{reseller}{id};
|
|
} else {
|
|
$form->values->{reseller_id} = $c->user->reseller_id;
|
|
}
|
|
delete $form->values->{reseller};
|
|
|
|
my $ft = File::Type->new();
|
|
foreach(qw/front_image mac_image front_thumbnail/){
|
|
if($form->values->{$_}) {
|
|
my $image = delete $form->values->{$_};
|
|
$form->values->{$_} = $image->slurp;
|
|
$form->values->{$_.'_type'} = $ft->mime_type($form->values->{$_});
|
|
}
|
|
}
|
|
|
|
#preparation of the connectable_models before store_and_process_device_model call
|
|
if(defined $form->values->{connectable_models}){
|
|
$form->values->{connectable_models} = decode_json($form->values->{connectable_models});
|
|
}
|
|
my $devmod = NGCP::Panel::Utils::Device::store_and_process_device_model($c, undef, $form->values);
|
|
|
|
delete $c->session->{created_objects}->{reseller};
|
|
$c->session->{created_objects}->{device} = { id => $devmod->id };
|
|
});
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
desc => $c->loc('Successfully created device model'),
|
|
);
|
|
} catch($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => $e,
|
|
desc => $c->loc('Failed to create device model'),
|
|
);
|
|
}
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
|
|
$c->stash(
|
|
devmod_create_flag => 1,
|
|
form => $form,
|
|
);
|
|
}
|
|
|
|
sub prepare_connectable :Private{
|
|
my ($self, $c, $model) = @_;
|
|
my $values = [];
|
|
|
|
my $connected_rs = $c->model('DB')->resultset('autoprov_device_extensions')->search_rs({
|
|
( $model->type eq 'phone' ? 'device_id' : 'extension_id' ) => $model->id,
|
|
});
|
|
for my $connected($connected_rs->all) {
|
|
push @$values, $connected->get_column ( $model->type eq 'phone' ? 'extension_id' : 'device_id' ) ;
|
|
}
|
|
return (encode_json($values), $values);
|
|
}
|
|
|
|
sub devmod_base :Chained('base') :PathPart('model') :CaptureArgs(1) {
|
|
my ($self, $c, $devmod_id) = @_;
|
|
|
|
unless(is_int($devmod_id)) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => "invalid device model id '$devmod_id'",
|
|
desc => $c->loc('Invalid device model id'),
|
|
);
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
my $devmod = $c->stash->{devmod_rs}->find($devmod_id,{'+columns' => [qw/mac_image front_image front_thumbnail/]});
|
|
unless($devmod) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => "device model with id '$devmod_id' not found",
|
|
desc => $c->loc('Device model not found'),
|
|
);
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
$c->stash(
|
|
devmod => $devmod,
|
|
);
|
|
}
|
|
|
|
sub devmod_delete :Chained('devmod_base') :PathPart('delete') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
|
my ($self, $c) = @_;
|
|
|
|
try {
|
|
$c->stash->{devmod}->delete;
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
data => { id => $c->stash->{devmod}->id,
|
|
model => $c->stash->{devmod}->model,
|
|
vendor => $c->stash->{devmod}->vendor },
|
|
desc => $c->loc('Device model successfully deleted'),
|
|
);
|
|
} catch($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => "failed to delete device model with id '".$c->stash->{devmod}->id."': $e",
|
|
desc => $c->loc('Failed to delete device model'),
|
|
);
|
|
}
|
|
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
|
|
sub devmod_edit :Chained('devmod_base') :PathPart('edit') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $posted = ($c->request->method eq 'POST');
|
|
my $form;
|
|
my $params = { $c->stash->{devmod}->get_inflated_columns };
|
|
$params->{linerange} = [];
|
|
foreach my $range($c->stash->{devmod}->autoprov_device_line_ranges->all) {
|
|
my $keys = [];
|
|
foreach my $key($range->annotations->all) {
|
|
push @{ $keys }, { x => $key->x, y => $key->y, labelpos => $key->position };
|
|
}
|
|
my $r = { $range->get_inflated_columns };
|
|
$r->{keys} = $keys;
|
|
push @{ $params->{linerange} }, $r;
|
|
}
|
|
#TODO: TO inflate/deflate, I think
|
|
foreach ( $c->model('DB')->resultset('autoprov_sync')->search_rs({
|
|
device_id =>$c->stash->{devmod}->id,
|
|
})->all ){
|
|
$params->{'bootstrap_config_'.$c->stash->{devmod}->bootstrap_method.'_'.$_->autoprov_sync_parameters->parameter_name} = $_->parameter_value;
|
|
}
|
|
my $credentials_rs = $c->model('DB')->resultset('autoprov_redirect_credentials')->search_rs({
|
|
'me.device_id' => $c->stash->{devmod}->id,
|
|
});
|
|
if($credentials_rs->first){
|
|
foreach ( qw/user password/ ){
|
|
$params->{'bootstrap_config_'.$c->stash->{devmod}->bootstrap_method.'_'.$_} = $credentials_rs->first->get_column($_);
|
|
}
|
|
}
|
|
#edit specific
|
|
($params->{connectable_models}) = $self->prepare_connectable($c, $c->stash->{devmod});
|
|
|
|
$params->{reseller}{id} = delete $params->{reseller_id};
|
|
$params = merge($params, $c->session->{created_objects});
|
|
$c->stash(edit_model => 1); # to make front_image optional
|
|
if($c->user->is_superuser) {
|
|
$form = NGCP::Panel::Form::get("NGCP::Panel::Form::Device::ModelAdmin", $c);
|
|
} else {
|
|
$form = NGCP::Panel::Form::get("NGCP::Panel::Form::Device::Model", $c);
|
|
}
|
|
if($posted) {
|
|
$c->req->params->{front_image} = $c->req->upload('front_image');
|
|
$c->req->params->{mac_image} = $c->req->upload('mac_image');
|
|
$c->req->params->{front_thumbnail} = $c->req->upload('front_thumbnail');
|
|
}
|
|
|
|
$form->process(
|
|
posted => $posted,
|
|
params => $c->request->params,
|
|
item => $params
|
|
);
|
|
NGCP::Panel::Utils::Navigation::check_form_buttons(
|
|
c => $c,
|
|
form => $form,
|
|
fields => {
|
|
'reseller.create' => $c->uri_for('/reseller/create'),
|
|
},
|
|
back_uri => $c->req->uri,
|
|
);
|
|
|
|
if($posted && $form->validated) {
|
|
try {
|
|
my $schema = $c->model('DB');
|
|
$schema->txn_do(sub {
|
|
if($c->user->is_superuser) {
|
|
$form->values->{reseller_id} = $form->values->{reseller}{id};
|
|
} else {
|
|
$form->values->{reseller_id} = $c->user->reseller_id;
|
|
}
|
|
delete $form->values->{reseller};
|
|
|
|
foreach (qw/front_image mac_image front_thumbnail/){
|
|
if($form->values->{$_}) {
|
|
my $image = delete $form->values->{$_};
|
|
$form->values->{$_} = $image->slurp;
|
|
$form->values->{$_.'_type'} = $image->type;
|
|
} else {
|
|
delete $form->values->{$_};
|
|
delete $form->values->{$_.'_type'};
|
|
}
|
|
}
|
|
|
|
#preparation of the connectable_models before store_and_process_device_model call
|
|
if(defined $form->values->{connectable_models}){
|
|
$form->values->{connectable_models} = decode_json($form->values->{connectable_models});
|
|
}
|
|
NGCP::Panel::Utils::Device::store_and_process_device_model($c, $c->stash->{devmod}, $form->values);
|
|
|
|
delete $c->session->{created_objects}->{reseller};
|
|
});
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
data => { id => $c->stash->{devmod}->id,
|
|
model => $c->stash->{devmod}->model,
|
|
vendor => $c->stash->{devmod}->vendor },
|
|
desc => $c->loc('Successfully updated device model'),
|
|
);
|
|
} catch($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => $e,
|
|
desc => $c->loc('Failed to update device model'),
|
|
);
|
|
}
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
|
|
$c->stash(
|
|
devmod_edit_flag => 1,
|
|
form => $form,
|
|
);
|
|
}
|
|
sub devmod_download_frontimage_by_profile :Chained('devprof_base') :PathPart('frontimage') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $devprof = $c->stash->{devprof};
|
|
my $devmod = $devprof->config->device;
|
|
unless($devmod->front_image) {
|
|
$c->response->body($c->loc('404 - No front image available for the model of this device profile'));
|
|
$c->response->status(404);
|
|
return;
|
|
}
|
|
$c->response->content_type($devmod->front_image_type);
|
|
$c->response->body($devmod->front_image);
|
|
}
|
|
|
|
sub devmod_download_frontimage :Chained('devmod_base') :PathPart('frontimage') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $devmod = $c->stash->{devmod};
|
|
unless($devmod->front_image) {
|
|
$c->response->body($c->loc('404 - No front image available for this device model'));
|
|
$c->response->status(404);
|
|
return;
|
|
}
|
|
$c->response->content_type($devmod->front_image_type);
|
|
$c->response->body($devmod->front_image);
|
|
}
|
|
|
|
sub devmod_download_macimage :Chained('devmod_base') :PathPart('macimage') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $devmod = $c->stash->{devmod};
|
|
unless($devmod->mac_image) {
|
|
$c->response->body($c->loc('404 - No mac image available for this device model'));
|
|
$c->response->status(404);
|
|
return;
|
|
}
|
|
$c->response->content_type($devmod->mac_image_type);
|
|
$c->response->body($devmod->mac_image);
|
|
}
|
|
|
|
sub devmod_download_frontthumbnail_by_profile :Chained('devprof_base') :PathPart('frontthumbnail') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $devprof = $c->stash->{devprof};
|
|
my $devmod = $devprof->config->device;
|
|
unless($devmod->front_thumbnail) {
|
|
$c->log->info("No device thumbnail for profile id " . $c->stash->{devprof}->id . ", redirecting to front image");
|
|
$c->res->redirect($c->uri_for_action("/device/devmod_download_frontimage_by_profile", [$c->stash->{devprof}->id]));
|
|
return;
|
|
}
|
|
$c->response->content_type($devmod->front_thumbnail_type);
|
|
$c->response->body($devmod->front_thumbnail);
|
|
}
|
|
|
|
sub devmod_download_frontthumbnail :Chained('devmod_base') :PathPart('frontthumbnail') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $devmod = $c->stash->{devmod};
|
|
unless($devmod->front_thumbnail) {
|
|
$c->log->info("No device thumbnail for model id " . $c->stash->{devmod}->id . ", redirecting to front image");
|
|
$c->res->redirect($c->uri_for_action("/device/devmod_download_frontimage", [$c->stash->{devmod}->id]));
|
|
return;
|
|
}
|
|
$c->response->content_type($devmod->front_thumbnail_type);
|
|
$c->response->body($devmod->front_thumbnail);
|
|
}
|
|
|
|
sub devfw_ajax :Chained('base') :PathPart('firmware/ajax') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $resultset = $c->stash->{devfw_rs};
|
|
NGCP::Panel::Utils::Datatables::process($c, $resultset, $c->stash->{devfw_dt_columns});
|
|
$c->detach( $c->view("JSON") );
|
|
}
|
|
|
|
sub devfw_create :Chained('base') :PathPart('firmware/create') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $posted = ($c->request->method eq 'POST');
|
|
my $form = NGCP::Panel::Form::get("NGCP::Panel::Form::Device::Firmware", $c);
|
|
|
|
my $params = {};
|
|
$params = merge($params, $c->session->{created_objects});
|
|
if($posted) {
|
|
$c->req->params->{data} = $c->req->upload('data');
|
|
}
|
|
$form->process(
|
|
posted => $posted,
|
|
params => $c->request->params,
|
|
item => $params
|
|
);
|
|
NGCP::Panel::Utils::Navigation::check_form_buttons(
|
|
c => $c,
|
|
form => $form,
|
|
fields => {
|
|
'device.create' => $c->uri_for('/device/model/create'),
|
|
},
|
|
back_uri => $c->req->uri,
|
|
);
|
|
|
|
if($posted && $form->validated) {
|
|
try {
|
|
my $schema = $c->model('DB');
|
|
$schema->txn_do(sub {
|
|
my $file = delete $form->values->{data};
|
|
$form->values->{filename} = $file->filename;
|
|
my $devmod = $c->stash->{devmod_rs}->find($form->values->{device}{id},{'+columns' => [qw/mac_image front_image front_thumbnail/]});
|
|
my $devfw = $devmod->create_related('autoprov_firmwares', $form->values);
|
|
if ($file->size) {
|
|
NGCP::Panel::Utils::DeviceFirmware::insert_firmware_data(
|
|
c => $c, fw_id => $devfw->id, data_fh => $file->fh
|
|
);
|
|
}
|
|
delete $c->session->{created_objects}->{device};
|
|
$c->session->{created_objects}->{firmware} = { id => $devfw->id };
|
|
});
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
desc => $c->loc('Successfully created device firmware'),
|
|
);
|
|
} catch($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => $e,
|
|
desc => $c->loc('Failed to create device firmware'),
|
|
);
|
|
}
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
|
|
$c->stash(
|
|
devfw_create_flag => 1,
|
|
form => $form,
|
|
);
|
|
}
|
|
|
|
sub devfw_base :Chained('base') :PathPart('firmware') :CaptureArgs(1) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
|
my ($self, $c, $devfw_id) = @_;
|
|
|
|
unless(is_int($devfw_id)) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => "invalid device firmware id '$devfw_id'",
|
|
desc => $c->loc('Invalid device firmware id'),
|
|
);
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
|
|
$c->stash->{devfw} = $c->stash->{devfw_rs}->find($devfw_id);
|
|
unless($c->stash->{devfw}) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => "device firmware with id '$devfw_id' not found",
|
|
desc => $c->loc('Device firmware not found'),
|
|
);
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
}
|
|
|
|
sub devfw_delete :Chained('devfw_base') :PathPart('delete') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
try {
|
|
$c->stash->{devfw}->delete;
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
data => { $c->stash->{devfw}->get_inflated_columns },
|
|
desc => $c->loc('Device firmware successfully deleted'),
|
|
);
|
|
} catch($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => "failed to delete device firmware with id '".$c->stash->{devfw}->id."': $e",
|
|
desc => $c->loc('Failed to delete device firmware'),
|
|
);
|
|
}
|
|
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
|
|
sub devfw_edit :Chained('devfw_base') :PathPart('edit') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $posted = ($c->request->method eq 'POST');
|
|
my $form;
|
|
my $params = { $c->stash->{devfw}->get_inflated_columns };
|
|
$params->{device}{id} = delete $params->{device_id};
|
|
$params = merge($params, $c->session->{created_objects});
|
|
if($posted) {
|
|
$c->req->params->{data} = $c->req->upload('data');
|
|
}
|
|
$form = NGCP::Panel::Form::get("NGCP::Panel::Form::Device::Firmware", $c);
|
|
|
|
$form->process(
|
|
posted => $posted,
|
|
params => $c->request->params,
|
|
item => $params
|
|
);
|
|
NGCP::Panel::Utils::Navigation::check_form_buttons(
|
|
c => $c,
|
|
form => $form,
|
|
fields => {
|
|
'device.create' => $c->uri_for('/device/model/create'),
|
|
},
|
|
back_uri => $c->req->uri,
|
|
);
|
|
|
|
if($posted && $form->validated) {
|
|
try {
|
|
my $schema = $c->model('DB');
|
|
$schema->txn_do(sub {
|
|
$form->values->{device_id} = $form->values->{device}{id};
|
|
delete $form->values->{device};
|
|
my $file = delete $form->values->{data};
|
|
$form->values->{filename} = $file->filename;
|
|
$c->stash->{devfw}->update($form->values);
|
|
if ($file->size) {
|
|
NGCP::Panel::Utils::DeviceFirmware::insert_firmware_data(
|
|
c => $c,
|
|
fw_id => $c->stash->{devfw}->id,
|
|
data_fh => $file->fh
|
|
);
|
|
}
|
|
delete $c->session->{created_objects}->{device};
|
|
});
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
desc => $c->loc('Successfully updated device firmware'),
|
|
);
|
|
} catch($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => $e,
|
|
desc => $c->loc('Failed to update device firmware'),
|
|
);
|
|
}
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
|
|
$c->stash(
|
|
devfw_edit_flag => 1,
|
|
form => $form,
|
|
);
|
|
}
|
|
|
|
sub devfw_download :Chained('devfw_base') :PathPart('download') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $fw = $c->stash->{devfw};
|
|
|
|
$c->response->header ('Content-Disposition' => 'attachment; filename="' . $fw->filename . '"');
|
|
$c->response->content_type('application/octet-stream');
|
|
$c->response->body(
|
|
NGCP::Panel::Utils::DeviceFirmware::get_firmware_data(
|
|
c => $c,
|
|
fw_id => $fw->id
|
|
));
|
|
}
|
|
|
|
sub devconf_ajax :Chained('base') :PathPart('config/ajax') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $resultset = $c->stash->{devconf_rs};
|
|
NGCP::Panel::Utils::Datatables::process($c, $resultset, $c->stash->{devconf_dt_columns});
|
|
$c->detach( $c->view("JSON") );
|
|
}
|
|
|
|
sub devconf_create :Chained('base') :PathPart('config/create') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $posted = ($c->request->method eq 'POST');
|
|
my $form = NGCP::Panel::Form::get("NGCP::Panel::Form::Device::Config", $c);
|
|
|
|
my $params = {};
|
|
$params = merge($params, $c->session->{created_objects});
|
|
$form->process(
|
|
posted => $posted,
|
|
params => $c->request->params,
|
|
item => $params
|
|
);
|
|
NGCP::Panel::Utils::Navigation::check_form_buttons(
|
|
c => $c,
|
|
form => $form,
|
|
fields => {
|
|
'device.create' => $c->uri_for('/device/model/create'),
|
|
},
|
|
back_uri => $c->req->uri,
|
|
);
|
|
|
|
if($posted && $form->validated) {
|
|
try {
|
|
my $schema = $c->model('DB');
|
|
$schema->txn_do(sub {
|
|
my $devmod = $c->stash->{devmod_rs}->find($form->values->{device}{id},{'+columns' => [qw/mac_image front_image front_thumbnail/]});
|
|
my $devconf = $devmod->create_related('autoprov_configs', $form->values);
|
|
delete $c->session->{created_objects}->{device};
|
|
$c->session->{created_objects}->{config} = { id => $devconf->id };
|
|
});
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
desc => $c->loc('Successfully created device configuration'),
|
|
);
|
|
} catch($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => $e,
|
|
desc => $c->loc('Failed to create device configuration'),
|
|
);
|
|
}
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
|
|
$c->stash(
|
|
devconf_create_flag => 1,
|
|
form => $form,
|
|
);
|
|
}
|
|
|
|
sub devconf_base :Chained('base') :PathPart('config') :CaptureArgs(1) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
|
my ($self, $c, $devconf_id) = @_;
|
|
|
|
unless(is_int($devconf_id)) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => "invalid device config id '$devconf_id'",
|
|
desc => $c->loc('Invalid device configuration id'),
|
|
);
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
|
|
$c->stash->{devconf} = $c->stash->{devconf_rs}->find($devconf_id,{'+columns' => 'data'});
|
|
unless($c->stash->{devconf}) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => "device configuration with id '$devconf_id' not found",
|
|
desc => $c->loc('Device configuration not found'),
|
|
);
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
}
|
|
|
|
sub devconf_delete :Chained('devconf_base') :PathPart('delete') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
try {
|
|
$c->stash->{devconf}->delete;
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
data => { $c->stash->{devconf}->get_inflated_columns },
|
|
desc => $c->loc('Device configuration successfully deleted'),
|
|
);
|
|
} catch($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => "failed to delete device configuration with id '".$c->stash->{devconf}->id."': $e",
|
|
desc => $c->loc('Failed to delete device configuration'),
|
|
);
|
|
}
|
|
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
|
|
sub devconf_edit :Chained('devconf_base') :PathPart('edit') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $posted = ($c->request->method eq 'POST');
|
|
my $form;
|
|
my $params = { $c->stash->{devconf}->get_inflated_columns };
|
|
$params->{device}{id} = delete $params->{device_id};
|
|
$params = merge($params, $c->session->{created_objects});
|
|
$form = NGCP::Panel::Form::get("NGCP::Panel::Form::Device::Config", $c);
|
|
|
|
$form->process(
|
|
posted => $posted,
|
|
params => $c->request->params,
|
|
item => $params
|
|
);
|
|
NGCP::Panel::Utils::Navigation::check_form_buttons(
|
|
c => $c,
|
|
form => $form,
|
|
fields => {
|
|
'device.create' => $c->uri_for('/device/model/create'),
|
|
},
|
|
back_uri => $c->req->uri,
|
|
);
|
|
|
|
if($posted && $form->validated) {
|
|
try {
|
|
my $schema = $c->model('DB');
|
|
$schema->txn_do(sub {
|
|
$form->values->{device_id} = $form->values->{device}{id};
|
|
delete $form->values->{device};
|
|
|
|
use Data::Printer; p $form->values;
|
|
$c->stash->{devconf}->update($form->values);
|
|
delete $c->session->{created_objects}->{device};
|
|
});
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
desc => $c->loc('Successfully updated device configuration'),
|
|
);
|
|
} catch($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => $e,
|
|
desc => $c->loc('Failed to update device configuration'),
|
|
);
|
|
}
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
|
|
$c->stash(
|
|
devconf_edit_flag => 1,
|
|
form => $form,
|
|
);
|
|
}
|
|
|
|
sub devconf_download :Chained('devconf_base') :PathPart('download') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $conf = $c->stash->{devconf};
|
|
|
|
$c->response->content_type($conf->content_type);
|
|
$c->response->body($conf->data);
|
|
}
|
|
|
|
sub devprof_ajax :Chained('base') :PathPart('profile/ajax') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $resultset = $c->stash->{devprof_rs};
|
|
NGCP::Panel::Utils::Datatables::process($c, $resultset, $c->stash->{devprof_dt_columns});
|
|
$c->detach( $c->view("JSON") );
|
|
}
|
|
|
|
sub devprof_create :Chained('base') :PathPart('profile/create') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $posted = ($c->request->method eq 'POST');
|
|
my $form = NGCP::Panel::Form::get("NGCP::Panel::Form::Device::Profile", $c);
|
|
|
|
my $params = {};
|
|
$params = merge($params, $c->session->{created_objects});
|
|
$form->process(
|
|
posted => $posted,
|
|
params => $c->request->params,
|
|
item => $params
|
|
);
|
|
NGCP::Panel::Utils::Navigation::check_form_buttons(
|
|
c => $c,
|
|
form => $form,
|
|
fields => {
|
|
'config.create' => $c->uri_for('/device/config/create'),
|
|
},
|
|
back_uri => $c->req->uri,
|
|
);
|
|
|
|
if($posted && $form->validated) {
|
|
try {
|
|
my $schema = $c->model('DB');
|
|
$schema->txn_do(sub {
|
|
$form->values->{config_id} = $form->values->{config}{id};
|
|
delete $form->values->{config};
|
|
|
|
$c->model('DB')->resultset('autoprov_profiles')->create($form->values);
|
|
|
|
delete $c->session->{created_objects}->{config};
|
|
});
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
desc => $c->loc('Successfully created device profile'),
|
|
);
|
|
} catch($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => $e,
|
|
desc => $c->loc('Failed to create device profile'),
|
|
);
|
|
}
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
|
|
$c->stash(
|
|
devprof_create_flag => 1,
|
|
form => $form,
|
|
);
|
|
}
|
|
|
|
sub devprof_base :Chained('base') :PathPart('profile') :CaptureArgs(1) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) :AllowedRole(subscriberadmin) {
|
|
my ($self, $c, $devprof_id) = @_;
|
|
|
|
unless(is_int($devprof_id)) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => "invalid device profile id '$devprof_id'",
|
|
desc => $c->loc('Invalid device profile id'),
|
|
);
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
|
|
$c->stash->{devprof} = $c->stash->{devprof_rs}->find($devprof_id);
|
|
unless($c->stash->{devprof}) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => "device profile with id '$devprof_id' not found",
|
|
desc => $c->loc('Device profile not found'),
|
|
);
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
}
|
|
|
|
sub devprof_extensions :Chained('devprof_base') :PathPart('extensions') :Args(0):Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) :AllowedRole(subscriberadmin) {
|
|
my ($self, $c) = @_;
|
|
|
|
|
|
my $rs = $c->stash->{devprof}->config->device->autoprov_extensions_link;
|
|
my $device_info = { $c->stash->{devprof}->config->device->get_inflated_columns };
|
|
foreach(qw/front_image mac_image front_thumbnail/){
|
|
delete $device_info->{$_};
|
|
}
|
|
|
|
my $data = {
|
|
'device' => $device_info,
|
|
'profile' => { $c->stash->{devprof}->get_inflated_columns},
|
|
'extensions' => { map {
|
|
$_->extension->id => {
|
|
$_->extension->get_inflated_columns,
|
|
'ranges' => [
|
|
map {
|
|
$_->get_inflated_columns,
|
|
'annotations' => [
|
|
map {{
|
|
$_->get_inflated_columns,
|
|
}} $_->annotations->all,
|
|
],
|
|
} $_->extension->autoprov_device_line_ranges->all
|
|
],
|
|
}
|
|
} $rs->all },
|
|
};
|
|
$c->stash(
|
|
aaData => $data,
|
|
iTotalRecords => 1,
|
|
iTotalDisplayRecords => 1,
|
|
iTotalRecordCountClipped => \0,
|
|
iTotalDisplayRecordCountClipped => \0,
|
|
sEcho => int($c->request->params->{sEcho} // 1),
|
|
);
|
|
|
|
$c->detach( $c->view("JSON") );
|
|
}
|
|
|
|
sub devprof_get_lines :Chained('devprof_base') :PathPart('lines/ajax') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) :AllowedRole(subscriberadmin) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $resultset = $c->stash->{devprof}->config->device->autoprov_device_line_ranges;
|
|
my $cols = NGCP::Panel::Utils::Datatables::set_columns($c, [
|
|
{ name => 'id', search => 1, title => $c->loc('ID') },
|
|
{ name => 'name', search => 1, title => $c->loc('Name') },
|
|
{ name => 'num_lines', search => 1, title => $c->loc('Number of Lines/Keys') },
|
|
{ name => 'can_private', search => 1, title => $c->loc('Private Line') },
|
|
{ name => 'can_shared', search => 1, title => $c->loc('Shared Line') },
|
|
{ name => 'can_blf', search => 1, title => $c->loc('BLF Key') },
|
|
{ name => 'can_speeddial', search => 1, title => $c->loc('SpeedDial') },
|
|
{ name => 'can_forward', search => 1, title => $c->loc('Forward') },
|
|
{ name => 'can_transfer', search => 1, title => $c->loc('Transfer') },
|
|
]);
|
|
NGCP::Panel::Utils::Datatables::process($c, $resultset, $cols);
|
|
$c->detach( $c->view("JSON") );
|
|
}
|
|
|
|
sub devprof_get_annotated_info :Chained('devprof_base') :PathPart('annolines/ajax') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) :AllowedRole(subscriberadmin) {
|
|
my ($self, $c) = @_;
|
|
$self->get_annotated_info($c, $c->stash->{devprof}->config->device );
|
|
}
|
|
|
|
sub devmod_get_annotated_info :Chained('devmod_base') :PathPart('annolines/ajax') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) :AllowedRole(subscriberadmin) {
|
|
my ($self, $c) = @_;
|
|
$self->get_annotated_info($c, $c->stash->{devmod} );
|
|
}
|
|
|
|
sub get_annotated_info :Private {
|
|
my ($self, $c, $devmod) = @_;
|
|
|
|
my $device_info = { $devmod->get_inflated_columns };
|
|
foreach(qw/front_image mac_image/){
|
|
delete $device_info->{$_};
|
|
}
|
|
my $gather_ranges_info = sub {
|
|
my $rs = shift;
|
|
return [ map {
|
|
{
|
|
$_->get_inflated_columns,
|
|
'annotations' => [
|
|
map {{
|
|
$_->get_inflated_columns,
|
|
}} $_->annotations->all,
|
|
],
|
|
}
|
|
}$rs->all
|
|
];
|
|
};
|
|
my $data = {
|
|
'device' => $device_info,
|
|
'ranges' => $gather_ranges_info->( $devmod->autoprov_device_line_ranges ),
|
|
'extensions' => { map {
|
|
$_->extension->id => {
|
|
$_->extension->get_inflated_columns,
|
|
'ranges' => $gather_ranges_info->( $_->extension->autoprov_device_line_ranges ),
|
|
}
|
|
} $devmod->autoprov_extensions_link->all },
|
|
};
|
|
|
|
$c->stash(
|
|
aaData => $data,
|
|
iTotalRecords => 1,
|
|
iTotalDisplayRecords => 1,
|
|
iTotalRecordCountClipped => \0,
|
|
iTotalDisplayRecordCountClipped => \0,
|
|
sEcho => int($c->request->params->{sEcho} // 1),
|
|
);
|
|
|
|
$c->detach( $c->view("JSON") );
|
|
}
|
|
sub devprof_delete :Chained('devprof_base') :PathPart('delete') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
|
my ($self, $c) = @_;
|
|
|
|
try {
|
|
$c->stash->{devprof}->delete;
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
data => { $c->stash->{devprof}->get_inflated_columns },
|
|
desc => $c->loc('Device profile successfully deleted'),
|
|
);
|
|
} catch($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => "failed to delete device profile with id '".$c->stash->{devprof}->id."': $e",
|
|
desc => $c->loc('Failed to delete device profile'),
|
|
);
|
|
}
|
|
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
|
|
sub devprof_edit :Chained('devprof_base') :PathPart('edit') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $posted = ($c->request->method eq 'POST');
|
|
my $form;
|
|
my $params = { $c->stash->{devprof}->get_inflated_columns };
|
|
$params->{config}{id} = delete $params->{config_id};
|
|
$params = merge($params, $c->session->{created_objects});
|
|
$form = NGCP::Panel::Form::get("NGCP::Panel::Form::Device::Profile", $c);
|
|
|
|
$form->process(
|
|
posted => $posted,
|
|
params => $c->request->params,
|
|
item => $params
|
|
);
|
|
NGCP::Panel::Utils::Navigation::check_form_buttons(
|
|
c => $c,
|
|
form => $form,
|
|
fields => {
|
|
'config.create' => $c->uri_for('/device/config/create'),
|
|
},
|
|
back_uri => $c->req->uri,
|
|
);
|
|
|
|
if($posted && $form->validated) {
|
|
try {
|
|
my $schema = $c->model('DB');
|
|
$schema->txn_do(sub {
|
|
$form->values->{config_id} = $form->values->{config}{id};
|
|
delete $form->values->{config};
|
|
|
|
$c->stash->{devprof}->update($form->values);
|
|
|
|
delete $c->session->{created_objects}->{config};
|
|
});
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
data => { $c->stash->{devprof}->get_inflated_columns },
|
|
desc => $c->loc('Successfully updated device profile'),
|
|
);
|
|
} catch($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => $e,
|
|
desc => $c->loc('Failed to update device profile'),
|
|
);
|
|
}
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
|
|
$c->stash(
|
|
devprof_edit_flag => 1,
|
|
form => $form,
|
|
);
|
|
}
|
|
|
|
sub dev_field_ajax :Chained('base') :PathPart('device/ajax') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $resultset = $c->stash->{fielddev_rs};
|
|
NGCP::Panel::Utils::Datatables::process($c, $resultset, $c->stash->{fielddev_dt_columns});
|
|
$c->detach( $c->view("JSON") );
|
|
}
|
|
|
|
sub dev_field_config :Chained('/') :PathPart('device/autoprov/config') :Args() {
|
|
my ($self, $c, $id) = @_;
|
|
my $opt = $c->req->params->{opt};
|
|
|
|
delete $c->response->cookies->{ngcp_panel_session};
|
|
$c->response->headers->remove_header('Connection');
|
|
$c->response->headers->remove_header('X-Catalyst');
|
|
$c->response->headers->push_header('Last-Modified' => DateTime::Format::HTTP->format_datetime());
|
|
|
|
$c->log->debug("SSL_CLIENT_M_DN: " . ($c->request->env->{SSL_CLIENT_M_DN} // ""));
|
|
unless(
|
|
($c->user_exists && ($c->user->roles eq "admin" || $c->user->roles eq "reseller")) ||
|
|
defined $c->request->env->{SSL_CLIENT_M_DN}
|
|
) {
|
|
$c->log->info("unauthenticated config access to id '$id' via ip " . $c->qs($c->req->address));
|
|
$c->response->content_type('text/plain');
|
|
if($c->config->{features}->{debug}) {
|
|
$c->response->body("403 - unauthenticated config access");
|
|
} else {
|
|
$c->response->body("403 - forbidden");
|
|
}
|
|
$c->response->status(403);
|
|
return;
|
|
}
|
|
|
|
unless($id) {
|
|
$c->response->content_type('text/plain');
|
|
if($c->config->{features}->{debug}) {
|
|
$c->response->body("404 - device id not given");
|
|
} else {
|
|
$c->response->body("404 - device not found");
|
|
}
|
|
$c->response->status(404);
|
|
return;
|
|
}
|
|
if($id =~ /^([0-9a-f]{12})\-directory\.xml$/) {
|
|
$c->log->debug("identified bootstrap path part '$id' as polycom directory request");
|
|
$c->res->redirect($c->uri_for_action("/pbx/polycom_directory_list", $id));
|
|
return;
|
|
}
|
|
|
|
my $filename = $id;
|
|
$id =~ s/\.(cfg|ini|xml)$//;
|
|
$id =~ s/^config\.//;
|
|
|
|
$id =~ s/^([^\=]+)\=0$/$1/;
|
|
$id = lc $id;
|
|
$id =~ s/\-[a-z]+$//;
|
|
$id =~ s/\-//g;
|
|
|
|
=pod
|
|
my $yealink_key;
|
|
if($id =~ s/_secure\.enc$//) {
|
|
# mark to serve master-encrypted device key instead of config
|
|
$yealink_key = $c->config->{autoprovisioning}->{yealink_key};
|
|
}
|
|
=cut
|
|
|
|
# print access details for external rate limiting (e.g. fail2ban)
|
|
my $ip;
|
|
if(defined $c->req->headers->header('X-Forwarded-For')) {
|
|
$ip = (split(/\s*,\s*/, $c->req->headers->header('X-Forwarded-For')))[0];
|
|
} else {
|
|
$ip = $c->req->address;
|
|
}
|
|
|
|
# example DN format is:
|
|
# /C=US/ST=708105B37234/L=CBT153908BX/O=Cisco Systems, Inc./OU=cisco.com/CN=SPA-525G2, MAC: 708105B37234, Serial: CBT153908BX/emailAddress=linksys-certadmin@cisco.com
|
|
# if check is enabled, lowercase both DN and given MAC, strip colons and dashes from both, and try to
|
|
# find given MAC as substring in DN
|
|
if ($c->config->{security}->{autoprov_ssl_mac_check}) {
|
|
my $dn = $c->request->env->{SSL_CLIENT_M_DN} // '';
|
|
$dn = lc($dn);
|
|
$dn =~ s/[:\-]//g;
|
|
if (index($dn, $id) == -1) {
|
|
$c->log->info("unauthorized config access to id '$id' from dn '" . $c->qs($dn) . "' via ip '" . $c->qs($ip) . "'");
|
|
$c->response->content_type('text/plain');
|
|
if($c->config->{features}->{debug}) {
|
|
$c->response->body("403 - unauthorized config access");
|
|
} else {
|
|
$c->response->body("403 - forbidden");
|
|
}
|
|
$c->response->status(403);
|
|
return;
|
|
}
|
|
}
|
|
|
|
my $dev = $c->model('DB')->resultset('autoprov_field_devices')->find({
|
|
identifier => $id
|
|
});
|
|
unless($dev) {
|
|
$c->log->warn("Unknown autoprov config '$id' for '" . $c->qs($ip) . "'");
|
|
$c->response->content_type('text/plain');
|
|
if($c->config->{features}->{debug}) {
|
|
$c->response->body("404 - device id '" . $id . "' not found");
|
|
} else {
|
|
$c->response->body("404 - device not found");
|
|
}
|
|
$c->response->status(404);
|
|
return;
|
|
}
|
|
$c->log->info("Serving autoprov config for '$id' to '" . $c->qs($ip) . "'");
|
|
|
|
=pod
|
|
if(defined $yealink_key && defined $dev->encryption_key) {
|
|
my $cipher = Crypt::Rijndael->new(
|
|
$yealink_key, Crypt::Rijndael::MODE_ECB()
|
|
);
|
|
$c->response->content_type('text/plain');
|
|
$c->response->body($cipher->encrypt($dev->encryption_key));
|
|
$c->response->status(200);
|
|
return;
|
|
}
|
|
=cut
|
|
|
|
my $model = $dev->profile->config->device;
|
|
|
|
my $schema = 'https';
|
|
my $host = $c->config->{deviceprovisioning}->{host} // $c->req->uri->host;
|
|
my $port = $c->config->{deviceprovisioning}->{port} // 1444;
|
|
my $cisco_port = $c->config->{deviceprovisioning}->{cisco_port} // 1447;
|
|
my $boot_port = $c->config->{deviceprovisioning}->{bootstrap_port} // 1445;
|
|
|
|
my $config_port = $dev->profile->config->device->bootstrap_method eq "http" ?
|
|
$cisco_port : $port;
|
|
|
|
my $vars = {
|
|
opt => $opt,
|
|
config => {
|
|
url => "$schema://$host:$config_port/device/autoprov/config/$id",
|
|
baseurl => "$schema://$host:$config_port/device/autoprov/config/",
|
|
mac => $id,
|
|
filename => $filename,
|
|
},
|
|
firmware => {
|
|
},
|
|
phone => {
|
|
vendor => $model->vendor,
|
|
model => $model->model,
|
|
stationname => $dev->station_name,
|
|
lineranges => [],
|
|
},
|
|
directory => {
|
|
spaurl => "$schema://$host:$cisco_port/pbx/directory/spa/$id",
|
|
panaurl => "$schema://$host:$port/pbx/directory/panasonic",
|
|
yeaurl => "$schema://$host:$port/pbx/directory/yealink?userid=$id",
|
|
name => 'PBX Address Book',
|
|
},
|
|
ldap => {
|
|
tls => $c->config->{ldap_device}->{tls},
|
|
ip => $c->config->{ldap_device}->{ip},
|
|
port => $c->config->{ldap_device}->{port},
|
|
dn => ',dc=hpbx,dc=sipwise,dc=com', # uid=xxx,o=contract-id added below
|
|
password => '', # set below
|
|
base => ',dc=hpbx,dc=sipwise,dc=com', # o=contract-id added below
|
|
nameattr => 'displayName',
|
|
phoneattr => 'telephoneNumber'
|
|
}
|
|
};
|
|
|
|
$vars->{firmware}->{baseurl} = "$schema://$host:$config_port/device/autoprov/firmware";
|
|
$vars->{firmware}->{booturl} = "http://$host:$boot_port/device/autoprov/firmware";
|
|
my $latest_fw = $c->model('DB')->resultset('autoprov_firmwares')->search({
|
|
device_id => $model->id,
|
|
}, {
|
|
order_by => { -desc => 'version' },
|
|
})->first;
|
|
if($latest_fw) {
|
|
$vars->{firmware}->{maxversion} = $latest_fw->version;
|
|
}
|
|
|
|
my $ldap_attr_set = 0;
|
|
my @lines = ();
|
|
my @field_models = $c->model('DB')->resultset('autoprov_devices')->search_rs({
|
|
'autoprov_field_device_lines.device_id' => $dev->id,
|
|
},
|
|
{
|
|
'join' => {'autoprov_device_line_ranges' => 'autoprov_field_device_lines'},
|
|
'+select' => [
|
|
{'' => \['me.type = ?', [ {} => 'phone' ] ], '-as' => 'is_phone_model' },
|
|
],
|
|
'+as' => ['is_phone_model'],
|
|
|
|
'group_by' => 'me.id',
|
|
'order_by' => { -desc => 'is_phone_model' },
|
|
}
|
|
)->all ;
|
|
foreach my $linerange( map { $_->autoprov_device_line_ranges->all } @field_models ) {
|
|
my $range = {
|
|
name => $linerange->name,
|
|
num_lines => $linerange->num_lines,
|
|
lines => [],
|
|
};
|
|
foreach my $line($linerange->autoprov_field_device_lines->search({ device_id => $dev->id })->all) {
|
|
my $sub = $line->provisioning_voip_subscriber;
|
|
|
|
my %sub_preferences_vars = (
|
|
display_name => $sub->username,
|
|
concurrent_max => 0,
|
|
concurrent_max_per_account => 0,
|
|
cc => '',
|
|
ac => '',
|
|
);
|
|
my $pref_rs = NGCP::Panel::Utils::Preferences::get_preferences_rs(
|
|
c => $c,
|
|
id => $sub->id,
|
|
type => 'usr',
|
|
#attribute => [keys %sub_preferences_vars],
|
|
);
|
|
my $preferences = get_inflated_columns_all($pref_rs, 'hash' => 'attribute', 'column' => 'value' );
|
|
foreach my $key (keys %sub_preferences_vars){
|
|
if(exists $preferences->{$key}){
|
|
$sub_preferences_vars{$key} = $preferences->{$key};
|
|
}
|
|
}
|
|
$sub_preferences_vars{displayname} = delete $sub_preferences_vars{display_name};
|
|
$sub_preferences_vars{device_id} = $line->deviceid_alias ? $line->deviceid_alias->username : undef;
|
|
# TODO: only push password for private/shared line?
|
|
my $aliases = [ $sub->voip_dbaliases->search({ is_primary => 0 })->get_column("username")->all ];
|
|
my $primary = $sub->voip_dbaliases->search({ is_primary => 1 })->get_column("username")->first;
|
|
|
|
push @{ $range->{lines} }, {
|
|
alias_numbers => $aliases,
|
|
primary_number => $primary,
|
|
extension => $sub->pbx_extension,
|
|
username => $sub->username,
|
|
domain => $sub->domain->domain,
|
|
password => $sub->password,
|
|
keynum => $line->key_num,
|
|
type => $line->line_type,
|
|
preferences => $preferences,
|
|
target_number => $line->target_number,
|
|
%sub_preferences_vars,
|
|
};
|
|
if(!$ldap_attr_set && $linerange->name eq "Full Keys" && $line->line_type eq "private") {
|
|
$vars->{ldap}->{dn} = "uid=".$sub->uuid . ",o=" . $sub->account_id . $vars->{ldap}->{dn};
|
|
$vars->{ldap}->{base} = "o=" . $sub->account_id . $vars->{ldap}->{base};
|
|
$vars->{ldap}->{password} = $sub->password;
|
|
$ldap_attr_set = 1;
|
|
}
|
|
}
|
|
push @{ $vars->{phone}->{lineranges} }, $range;
|
|
}
|
|
my $preferences_device;
|
|
my $preferences_device_dynamic;
|
|
my $preferences_id = {
|
|
'fielddev' => $dev->id,
|
|
'dev' => $model->id,
|
|
'devprof' => $dev->profile->id,
|
|
};
|
|
foreach my $type (keys %$preferences_id) {
|
|
my $pref_rs = NGCP::Panel::Utils::Preferences::get_preferences_rs(
|
|
c => $c,
|
|
id => $preferences_id->{$type},
|
|
type => $type,
|
|
);
|
|
my $pref_rs_dynamic = $pref_rs->search_rs({
|
|
'attribute.dynamic' => 1,
|
|
}, {
|
|
'+select' => [\'replace(attribute.attribute,"__","")' ],
|
|
'+as' => ['attribute_normalized'],
|
|
});
|
|
$preferences_device_dynamic->{$type} = get_inflated_columns_all($pref_rs_dynamic,
|
|
'hash' => 'attribute_normalized',
|
|
'column' => 'value'
|
|
);
|
|
my $pref_rs_static = $pref_rs->search_rs({
|
|
'attribute.dynamic' => 0,
|
|
});
|
|
$preferences_device->{$type} = get_inflated_columns_all($pref_rs_static,
|
|
'hash' => 'attribute',
|
|
'column' => 'value'
|
|
);
|
|
}
|
|
my %preferences_device = (
|
|
'model' => $preferences_device->{dev},
|
|
'profile' => $preferences_device->{devprof},
|
|
'persistent' => {
|
|
'model' => {%{$preferences_device->{dev}}},
|
|
'profile' => {%{$preferences_device->{devprof}}},
|
|
'device' => $preferences_device->{fielddev},
|
|
},
|
|
'dynamic' => {
|
|
'model' => $preferences_device_dynamic->{dev},
|
|
'profile' => $preferences_device_dynamic->{devprof},
|
|
'device' => $preferences_device_dynamic->{fielddev},
|
|
},
|
|
'device' => {
|
|
%{$preferences_device->{dev}},
|
|
%{$preferences_device_dynamic->{dev}},
|
|
%{$preferences_device->{devprof}},
|
|
%{$preferences_device_dynamic->{devprof}},
|
|
%{$preferences_device->{fielddev}},
|
|
%{$preferences_device_dynamic->{fielddev}},
|
|
}
|
|
);
|
|
$vars->{preferences} //= {};
|
|
$vars->{preferences}->{device} = \%preferences_device;
|
|
|
|
my $data = $dev->profile->config->data;
|
|
|
|
my $var_hash = md5_hex(freeze $vars);
|
|
my $cfg_hash = md5_hex($data);
|
|
$vars->{checksum} = md5_hex($var_hash . $cfg_hash);
|
|
|
|
my $processed_data = "";
|
|
my $t = Template->new({
|
|
PLUGIN_BASE => 'NGCP::Panel::Template::Plugin',
|
|
});
|
|
$t->process(\$data, $vars, \$processed_data) || do {
|
|
my $error = $t->error();
|
|
my $msg = "error processing template, type=".$error->type.", info='".$error->info."'";
|
|
$c->log->error($msg);
|
|
$c->response->body("500 - error creating template:\n$msg");
|
|
$c->response->status(500);
|
|
return;
|
|
};
|
|
if($model->vendor eq "Audiocodes") {
|
|
$processed_data .= "\r\n\r\n";
|
|
}
|
|
|
|
$c->log->debug("providing config to $id");
|
|
$c->log->debug($processed_data);
|
|
|
|
=pod
|
|
if(defined $dev->encryption_key) {
|
|
# yealink uses weak ECB mode, but well...
|
|
my $cipher = Crypt::Rijndael->new(
|
|
$dev->encryption_key, Crypt::Rijndael::MODE_ECB()
|
|
);
|
|
$c->response->content_type("application/octet-stream");
|
|
$c->response->body($cipher->encrypt($processed_data));
|
|
} else {
|
|
=cut
|
|
my $result = $self->dev_field_encrypt( $c, $dev, $processed_data, $vars);
|
|
$c->response->content_type($result->{content_type});
|
|
$c->response->body(${$result->{content}});
|
|
}
|
|
|
|
sub dev_field_encrypt :Private{
|
|
my ($self, $c, $dev, $processed_data, $vars) = @_;
|
|
|
|
my $result = {'content' => \$processed_data };
|
|
|
|
my $model = $dev->profile->config->device;
|
|
|
|
my $module = 'NGCP::Panel::Utils::Device';
|
|
my $method = $module->can(lc($model->vendor.'_fielddev_config_process'));
|
|
if ( $method ) {
|
|
$result->{content_type} //= 'application/octet-stream';
|
|
$method->(\$processed_data, $result, 'field_device' => $dev, 'vars' => $vars );
|
|
}else{
|
|
$result->{content_type} //= $dev->profile->config->content_type;
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
sub dev_field_bootstrap :Chained('/') :PathPart('device/autoprov/bootstrap') :Args() {
|
|
my ($self, $c, @id) = @_;
|
|
my $opt = $c->req->params->{opt};
|
|
my $id;
|
|
|
|
delete $c->response->cookies->{ngcp_panel_session};
|
|
$c->response->headers->remove_header('Connection');
|
|
$c->response->headers->remove_header('X-Catalyst');
|
|
$c->response->headers->push_header('Last-Modified' => DateTime::Format::HTTP->format_datetime());
|
|
|
|
|
|
foreach my $did (@id) {
|
|
$c->log->debug("checking bootstrap path part '$did'");
|
|
$did =~ s/\.(cfg|ini|xml)$//;
|
|
$did =~ s/^config\.//;
|
|
$did =~ s/^([^\=]+)\=0$/$1/;
|
|
$did = lc $did;
|
|
$did =~ s/\-[a-z]+$//;
|
|
$did =~ s/\-//g;
|
|
if($did =~ /^[0-9a-f]{12}$/) {
|
|
$c->log->debug("identified bootstrap path part '$did' as valid device id");
|
|
$id = $did;
|
|
last;
|
|
}
|
|
}
|
|
unless($id) {
|
|
$c->response->content_type('text/plain');
|
|
if($c->config->{features}->{debug}) {
|
|
$c->response->body("404 - device id not given");
|
|
} else {
|
|
$c->response->body("404 - device not found");
|
|
}
|
|
$c->response->status(404);
|
|
return;
|
|
}
|
|
|
|
my $ip;
|
|
if(defined $c->req->headers->header('X-Forwarded-For')) {
|
|
$ip = (split(/\s*,\s*/, $c->req->headers->header('X-Forwarded-For')))[0];
|
|
} else {
|
|
$ip = $c->req->address;
|
|
}
|
|
|
|
my $dev = $c->model('DB')->resultset('autoprov_field_devices')->find({
|
|
identifier => $id
|
|
});
|
|
unless($dev) {
|
|
$c->log->warn("Unknown autoprov bootstrap config '$id' for '" . $c->qs($ip) . "'");
|
|
$c->response->content_type('text/plain');
|
|
if($c->config->{features}->{debug}) {
|
|
$c->response->body("404 - device id '" . $id . "' not found");
|
|
} else {
|
|
$c->response->body("404 - device not found");
|
|
}
|
|
$c->response->status(404);
|
|
return;
|
|
}
|
|
$c->log->info("Serving autoprov bootstrap config for '$id' to '" . $c->qs($ip) . "'");
|
|
|
|
my $model = $dev->profile->config->device;
|
|
|
|
my $schema = 'https';
|
|
my $host = $c->config->{deviceprovisioning}->{host} // $c->req->uri->host;
|
|
my $port = $c->config->{deviceprovisioning}->{port} // 1444;
|
|
my $boot_port = $c->config->{deviceprovisioning}->{bootstrap_port} // 1445;
|
|
my $cisco_port = $c->config->{deviceprovisioning}->{cisco_port} // 1447;
|
|
|
|
my $config_port = $dev->profile->config->device->bootstrap_method eq "http" ?
|
|
$cisco_port : $port;
|
|
|
|
my $vars = {
|
|
opt => $opt,
|
|
config => {
|
|
url => "$schema://$host:$config_port/device/autoprov/config/$id",
|
|
baseurl => "$schema://$host:$config_port/device/autoprov/config/",
|
|
caurl => "http://$host:$boot_port/device/autoprov/cacert",
|
|
ca => $c->model('CA')->get_provisioning_ca_cert($c),
|
|
mac => $id,
|
|
bootstrap => 1,
|
|
},
|
|
firmware => {
|
|
baseurl => "$schema://$host:$config_port/device/autoprov/firmware",
|
|
booturl => "http://$host:$boot_port/device/autoprov/firmware",
|
|
},
|
|
};
|
|
|
|
my $latest_fw = $c->model('DB')->resultset('autoprov_firmwares')->search({
|
|
device_id => $model->id,
|
|
}, {
|
|
order_by => { -desc => 'version' },
|
|
})->first;
|
|
if($latest_fw) {
|
|
$vars->{firmware}->{maxversion} = $latest_fw->version;
|
|
}
|
|
|
|
my $data = $dev->profile->config->data;
|
|
my $processed_data = "";
|
|
my $t = Template->new({
|
|
PLUGIN_BASE => 'NGCP::Panel::Template::Plugin',
|
|
});
|
|
$t->process(\$data, $vars, \$processed_data) || do {
|
|
my $error = $t->error();
|
|
my $msg = "error processing template, type=".$error->type.", info='".$error->info."'";
|
|
$c->log->error($msg);
|
|
$c->response->body("500 - error creating template:\n$msg");
|
|
$c->response->status(500);
|
|
return;
|
|
};
|
|
if($model->vendor eq "Audiocodes") {
|
|
$processed_data .= "\r\n\r\n";
|
|
}
|
|
|
|
$c->log->debug("providing config to $id");
|
|
$c->log->debug($processed_data);
|
|
|
|
my $result = $self->dev_field_encrypt( $c, $dev, $processed_data, $vars);
|
|
$c->response->content_type($result->{content_type});
|
|
$c->response->body(${$result->{content}});
|
|
}
|
|
|
|
sub dev_servercert :Chained('/') :PathPart('device/autoprov/servercert') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
my $cert = $c->model('CA')->get_provisioning_server_cert($c);
|
|
$c->res->headers(HTTP::Headers->new(
|
|
'Content-Type' => 'application/octet-stream',
|
|
#'Content-Disposition' => sprintf('attachment; filename=%s', "provisioning-certificate.pem")
|
|
));
|
|
$c->res->body($cert);
|
|
return;
|
|
}
|
|
|
|
sub dev_cacert :Chained('/') :PathPart('device/autoprov/cacert') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
my $cert = $c->model('CA')->get_provisioning_ca_cert($c);
|
|
$c->res->headers(HTTP::Headers->new(
|
|
'Content-Type' => 'application/octet-stream',
|
|
#'Content-Disposition' => sprintf('attachment; filename=%s', "provisioning-certificate.pem")
|
|
));
|
|
$c->res->body($cert);
|
|
return;
|
|
}
|
|
|
|
sub dev_field_firmware_base :Chained('/') :PathPart('device/autoprov/firmware') :CaptureArgs(1) {
|
|
my ($self, $c, $id) = @_;
|
|
|
|
unless($id) {
|
|
$c->response->content_type('text/plain');
|
|
if($c->config->{features}->{debug}) {
|
|
$c->response->body("404 - device id not given");
|
|
} else {
|
|
$c->response->body("404 - device not found");
|
|
}
|
|
$c->response->status(404);
|
|
$c->detach();
|
|
return;
|
|
}
|
|
$id =~ s/^([^\=]+)\=0$/$1/;
|
|
$id = lc $id;
|
|
|
|
my $dev = $c->model('DB')->resultset('autoprov_field_devices')->find({
|
|
identifier => $id
|
|
});
|
|
unless($dev) {
|
|
$c->response->content_type('text/plain');
|
|
if($c->config->{features}->{debug}) {
|
|
$c->response->body("404 - device id '" . $id . "' not found");
|
|
} else {
|
|
$c->response->body("404 - device not found");
|
|
}
|
|
$c->response->status(404);
|
|
$c->detach();
|
|
return;
|
|
}
|
|
|
|
$c->stash->{dev} = $dev;
|
|
}
|
|
|
|
sub dev_field_firmware_download :Chained('dev_field_firmware_base') :PathPart('version') :Args(1) {
|
|
my ($self, $c, $ver) = @_;
|
|
my $tag = "";
|
|
|
|
my $rs = $c->stash->{dev}->profile->config->device->autoprov_firmwares->search({
|
|
device_id => $c->stash->{dev}->profile->config->device->id,
|
|
version => { '=' => $ver },
|
|
});
|
|
|
|
unless($rs->first) {
|
|
$tag = $ver;
|
|
$rs = $c->stash->{dev}->profile->config->device->autoprov_firmwares->search({
|
|
device_id => $c->stash->{dev}->profile->config->device->id,
|
|
tag => { '=' => $tag },
|
|
});
|
|
}
|
|
|
|
my $fw = $rs->first;
|
|
unless($fw) {
|
|
$c->response->content_type('text/plain');
|
|
if(defined $tag && length $tag > 0) {
|
|
$c->response->body("404 - firmware tag '$tag' is latest");
|
|
} else {
|
|
$c->response->body("404 - firmware version '$ver' is latest");
|
|
}
|
|
$c->response->status(404);
|
|
return;
|
|
}
|
|
|
|
$c->response->header ('Content-Disposition' => 'attachment; filename="' . $fw->filename . '"');
|
|
$c->response->content_type('application/octet-stream');
|
|
NGCP::Panel::Utils::DeviceFirmware::get_firmware_data_into_body(
|
|
c => $c,
|
|
fw_id => $fw->id
|
|
);
|
|
}
|
|
|
|
sub dev_field_firmware_version_base :Chained('dev_field_firmware_base') :PathPart('from') :CaptureArgs(1) {
|
|
my ($self, $c, $fwver) = @_;
|
|
|
|
unless(defined $fwver) {
|
|
$c->response->content_type('text/plain');
|
|
if($c->config->{features}->{debug}) {
|
|
$c->response->body("404 - firmware name not given");
|
|
} else {
|
|
$c->response->body("404 - firmware not found");
|
|
}
|
|
$c->response->status(404);
|
|
$c->detach();
|
|
return;
|
|
}
|
|
|
|
$c->stash->{dev_fw_string} = $fwver;
|
|
my $dev = $c->stash->{dev};
|
|
$c->stash->{fw_rs} = $dev->profile->config->device->autoprov_firmwares;
|
|
}
|
|
|
|
sub dev_field_firmware_next :Chained('dev_field_firmware_version_base') :PathPart('next') :Args {
|
|
my ($self, $c, $tag) = @_;
|
|
|
|
my $rs = $c->stash->{fw_rs}->search({
|
|
device_id => $c->stash->{dev}->profile->config->device->id,
|
|
version => { '>' => $c->stash->{dev_fw_string} },
|
|
}, {
|
|
order_by => { -asc => 'version' },
|
|
});
|
|
if(defined $tag && length $tag > 0) {
|
|
$rs = $rs->search({
|
|
tag => $tag,
|
|
});
|
|
}
|
|
if(defined $c->req->params->{q}) {
|
|
$rs = $rs->search({
|
|
version => { 'like' => $c->req->params->{q} . '%' },
|
|
});
|
|
}
|
|
|
|
my $fw = $rs->first;
|
|
unless($fw) {
|
|
$c->response->content_type('text/plain');
|
|
if(defined $tag && length $tag > 0) {
|
|
$c->response->body("404 - current firmware with tag '$tag' is latest");
|
|
} else {
|
|
$c->response->body("404 - current firmware version '" . $c->stash->{dev_fw_string} . "' is latest");
|
|
}
|
|
$c->response->status(404);
|
|
return;
|
|
}
|
|
|
|
$c->response->header ('Content-Disposition' => 'attachment; filename="' . $fw->filename . '"');
|
|
$c->response->content_type('application/octet-stream');
|
|
NGCP::Panel::Utils::DeviceFirmware::get_firmware_data_into_body(
|
|
c => $c,
|
|
fw_id => $fw->id
|
|
);
|
|
}
|
|
|
|
sub dev_field_firmware_latest :Chained('dev_field_firmware_version_base') :PathPart('latest') :Args {
|
|
my ($self, $c, $tag) = @_;
|
|
|
|
my $rs = $c->stash->{fw_rs}->search({
|
|
device_id => $c->stash->{dev}->profile->config->device->id,
|
|
version => { '>' => $c->stash->{dev_fw_string} },
|
|
}, {
|
|
order_by => { -desc => 'version' },
|
|
});
|
|
if(defined $tag && length $tag > 0) {
|
|
$rs = $rs->search({
|
|
tag => $tag,
|
|
});
|
|
}
|
|
if(defined $c->req->params->{q}) {
|
|
$rs = $rs->search({
|
|
version => { 'like' => $c->req->params->{q} . '%' },
|
|
});
|
|
}
|
|
|
|
my $fw = $rs->first;
|
|
unless($fw) {
|
|
$c->response->content_type('text/plain');
|
|
if(defined $tag && length $tag > 0) {
|
|
$c->response->body("404 - current firmware with tag '$tag' is latest");
|
|
} else {
|
|
$c->response->body("404 - current firmware version '" . $c->stash->{dev_fw_string} . "' is latest");
|
|
}
|
|
$c->response->status(404);
|
|
return;
|
|
}
|
|
|
|
$c->response->header ('Content-Disposition' => 'attachment; filename="' . $fw->filename . '"');
|
|
$c->response->content_type('application/octet-stream');
|
|
NGCP::Panel::Utils::DeviceFirmware::get_firmware_data_into_body(
|
|
c => $c,
|
|
fw_id => $fw->id
|
|
);
|
|
}
|
|
|
|
sub devices_preferences_list :Chained('devmod_base') :PathPart('preferences') :CaptureArgs(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $dev_pref_rs = NGCP::Panel::Utils::Preferences::get_preferences_rs(
|
|
c => $c,
|
|
type => 'dev',
|
|
id => $c->stash->{devmod}->id,
|
|
);
|
|
|
|
my $pref_values = get_inflated_columns_all($dev_pref_rs,'hash' => 'attribute', 'column' => 'value', 'force_array' => 1);
|
|
|
|
NGCP::Panel::Utils::Preferences::load_preference_list(
|
|
c => $c,
|
|
pref_values => $pref_values,
|
|
#we don't need fielddev_pref flag, because it always will be just more narrow than dev_pref.
|
|
dev_pref => 1,
|
|
search_conditions => [{
|
|
'attribute' =>
|
|
[ -or =>
|
|
{ 'like' => 'vnd_'.lc($c->stash->{devmod}->vendor).'%' },
|
|
{'-not_like' => 'vnd_%' },
|
|
],
|
|
#relation type is defined by preference flag dev_pref,
|
|
#so here we select only linked to the current model, or not linked to any model at all
|
|
'-or' => [
|
|
'voip_preference_relations.autoprov_device_id' => $c->stash->{devmod}->id,
|
|
'voip_preference_relations.reseller_id' => $c->stash->{devmod}->reseller_id,
|
|
'voip_preference_relations.voip_preference_id' => undef
|
|
],
|
|
},{
|
|
join => {'voip_preferences' => 'voip_preference_relations'},
|
|
}
|
|
]
|
|
);
|
|
|
|
$c->stash(template => 'device/preferences.tt');
|
|
return;
|
|
}
|
|
|
|
sub devices_preferences_root :Chained('devices_preferences_list') :PathPart('') :Args(0) {
|
|
return;
|
|
}
|
|
|
|
sub devices_preferences_base :Chained('devices_preferences_list') :PathPart('') :CaptureArgs(1) {
|
|
my ($self, $c, $pref_id) = @_;
|
|
|
|
$c->stash->{preference_meta} = $c->model('DB')
|
|
->resultset('voip_preferences')
|
|
->search({
|
|
-or => ['voip_preferences_enums.dev_pref' => 1,
|
|
'voip_preferences_enums.dev_pref' => undef],
|
|
},{
|
|
prefetch => 'voip_preferences_enums',
|
|
})
|
|
->find({id => $pref_id});
|
|
|
|
$c->stash->{preference} = $c->model('DB')
|
|
->resultset('voip_dev_preferences')
|
|
->search({
|
|
'attribute_id' => $pref_id,
|
|
'device_id' => $c->stash->{devmod}->id,
|
|
});
|
|
return;
|
|
}
|
|
|
|
sub devices_preferences_create :Chained('devices_preferences_list') :PathPart('create') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
my $posted = ($c->request->method eq 'POST');
|
|
my $form = NGCP::Panel::Form::get("NGCP::Panel::Form::Device::Preference", $c);
|
|
|
|
my $params = {};
|
|
$params = merge($params, $c->session->{created_objects});
|
|
$form->process(
|
|
posted => $posted,
|
|
params => $c->request->params,
|
|
item => $params
|
|
);
|
|
|
|
if($posted && $form->validated) {
|
|
try {
|
|
my $schema = $c->model('DB');
|
|
$schema->txn_do(sub {
|
|
my $resource = $form->values;
|
|
|
|
$resource->{dev_pref} = 1;
|
|
$resource->{autoprov_device_id} = $c->stash->{devmod}->id;
|
|
|
|
my $preference = NGCP::Panel::Utils::Preferences::create_dynamic_preference(
|
|
$c, $resource,
|
|
group_name => 'CPBX Device Administration',
|
|
);
|
|
|
|
$c->session->{created_objects}->{preference} = { id => $preference->id };
|
|
});
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
desc => $c->loc('Successfully created device model preference'),
|
|
);
|
|
} catch($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => $e,
|
|
desc => $c->loc('Failed to create device model preference'),
|
|
);
|
|
}
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
$c->stash(
|
|
create_flag => 1,
|
|
form => $form,
|
|
);
|
|
}
|
|
|
|
sub devices_preferences_editmeta :Chained('devices_preferences_base') :PathPart('editmeta') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
my $posted = ($c->request->method eq 'POST');
|
|
my $form = NGCP::Panel::Form::get("NGCP::Panel::Form::Device::Preference", $c);
|
|
|
|
my $params = { $c->stash->{preference_meta}->get_inflated_columns };
|
|
$params->{enum} = [ map { {$_->get_inflated_columns} } $c->stash->{preference_meta}->voip_preferences_enums->all ];
|
|
$params = merge($params, $c->session->{created_objects});
|
|
$form->process(
|
|
posted => $posted,
|
|
params => $c->request->params,
|
|
item => $params
|
|
);
|
|
|
|
if($posted && $form->validated) {
|
|
try {
|
|
my $schema = $c->model('DB');
|
|
$schema->txn_do(sub {
|
|
my $resource = $form->values;
|
|
|
|
$resource->{dev_pref} = 1;
|
|
$resource->{autoprov_device_id} = $c->stash->{devmod}->id;
|
|
|
|
NGCP::Panel::Utils::Preferences::update_dynamic_preference(
|
|
$c, $c->stash->{preference_meta}, $resource
|
|
);
|
|
});
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
desc => $c->loc('Successfully updated device model preference'),
|
|
);
|
|
} catch($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => $e,
|
|
desc => $c->loc('Failed to update device model preference'),
|
|
);
|
|
}
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
$c->stash(
|
|
editmeta_flag => 1,
|
|
form => $form,
|
|
);
|
|
}
|
|
|
|
sub devices_preferences_delete :Chained('devices_preferences_base') :PathPart('delete') :Args(0):Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
|
my ($self, $c) = @_;
|
|
|
|
try {
|
|
NGCP::Panel::Utils::Preferences::delete_dynamic_preference(
|
|
$c, $c->stash->{preference_meta}
|
|
);
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
data => { id => $c->stash->{preference_meta}->id,
|
|
attribute => $c->stash->{preference_meta}->attribute },
|
|
desc => $c->loc('Device model preference successfully deleted'),
|
|
);
|
|
} catch($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => "failed to delete device model preference with id '".$c->stash->{preference_meta}->id."': $e",
|
|
desc => $c->loc('Failed to delete device model preference'),
|
|
);
|
|
}
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/device'));
|
|
}
|
|
|
|
|
|
sub devices_preferences_edit :Chained('devices_preferences_base') :PathPart('edit') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
$c->stash(edit_preference => 1);
|
|
|
|
my @enums = $c->stash->{preference_meta}
|
|
->voip_preferences_enums
|
|
->all;
|
|
|
|
my $pref_rs = $c->stash->{devmod}->voip_dev_preferences;
|
|
NGCP::Panel::Utils::Preferences::create_preference_form(
|
|
c => $c,
|
|
pref_rs => $pref_rs,
|
|
enums => \@enums,
|
|
base_uri => $c->uri_for_action('/device/devices_preferences_root', [@{ $c->req->captures }[0]] ),
|
|
edit_uri => $c->uri_for_action('/device/devices_preferences_edit', $c->req->captures ),
|
|
);
|
|
return;
|
|
}
|
|
|
|
sub profile_preferences_list :Chained('devprof_base') :PathPart('preferences') :CaptureArgs(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $devprof_pref_rs = NGCP::Panel::Utils::Preferences::get_preferences_rs(
|
|
c => $c,
|
|
type => 'devprof',
|
|
id => $c->stash->{devprof}->id,
|
|
);
|
|
my $pref_values = get_inflated_columns_all($devprof_pref_rs,'hash' => 'attribute', 'column' => 'value', 'force_array' => 1);
|
|
|
|
NGCP::Panel::Utils::Preferences::load_preference_list(
|
|
c => $c,
|
|
pref_values => $pref_values,
|
|
'devprof_pref' => 1,
|
|
search_conditions => {
|
|
'-or' => [
|
|
{'attribute' => {'like' => 'vnd_'.lc($c->stash->{devprof}->config->device->vendor).'%' } },
|
|
{'attribute' => {'-not_like' => 'vnd_%' }}
|
|
],
|
|
}
|
|
);
|
|
|
|
$c->stash(template => 'device/profilepreferences.tt');
|
|
return;
|
|
}
|
|
|
|
sub profile_preferences_root :Chained('profile_preferences_list') :PathPart('') :Args(0) {
|
|
return;
|
|
}
|
|
|
|
sub profile_preferences_base :Chained('profile_preferences_list') :PathPart('') :CaptureArgs(1) {
|
|
my ($self, $c, $pref_id) = @_;
|
|
|
|
$c->stash->{preference_meta} = $c->model('DB')
|
|
->resultset('voip_preferences')
|
|
->search({
|
|
-or => ['voip_preferences_enums.devprof_pref' => 1,
|
|
'voip_preferences_enums.devprof_pref' => undef],
|
|
},{
|
|
prefetch => 'voip_preferences_enums',
|
|
})
|
|
->find({id => $pref_id});
|
|
|
|
$c->stash->{preference} = $c->model('DB')
|
|
->resultset('voip_devprof_preferences')
|
|
->search({
|
|
'attribute_id' => $pref_id,
|
|
'profile_id' => $c->stash->{devprof}->id,
|
|
});
|
|
return;
|
|
}
|
|
|
|
sub profile_preferences_edit :Chained('profile_preferences_base') :PathPart('edit') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
$c->stash(edit_preference => 1);
|
|
|
|
my @enums = $c->stash->{preference_meta}
|
|
->voip_preferences_enums
|
|
->all;
|
|
|
|
my $pref_rs = $c->stash->{devprof}->voip_devprof_preferences;
|
|
NGCP::Panel::Utils::Preferences::create_preference_form(
|
|
c => $c,
|
|
pref_rs => $pref_rs,
|
|
enums => \@enums,
|
|
base_uri => $c->uri_for_action('/device/profile_preferences_root', [@{ $c->req->captures }[0]] ),
|
|
edit_uri => $c->uri_for_action('/device/profile_preferences_edit', $c->req->captures ),
|
|
);
|
|
return;
|
|
}
|
|
|
|
1;
|
|
|
|
__END__
|
|
|
|
=head1 NAME
|
|
|
|
NGCP::Panel::Controller::Device
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
A helper to manipulate devices data
|
|
|
|
=head1 AUTHOR
|
|
|
|
Sipwise Development Team
|
|
|
|
=head1 LICENSE
|
|
|
|
This library is free software. You can redistribute it and/or modify
|
|
it under the same terms as Perl itself.
|
|
|
|
=cut
|
|
|
|
# vim: set tabstop=4 expandtab:
|