TT#108162 Reseller branding primary and secondary colors

* add color pickers and store the hex code of the colors
  inside the branding table in panel UI
* implement /api/resellerbrandings endpoint, where all things
  related to reseller branding can be managed; the branding
  logo will still be retrieved using /api/resellerrandinglogos

Change-Id: Ib7ed364811acf67ffd62252d9799a0af8b91e9bc
mr9.4
Flaviu Mates 5 years ago committed by Kirill Solomko
parent d76dff7fc4
commit 8bc9a3974c

@ -21,3 +21,4 @@ ngcp-panel source: source-is-missing share/static/js/plugins/validate/jquery.val
ngcp-panel source: source-is-missing share/static/js/swaggerui/swagger-ui-bundle.js *
ngcp-panel source: source-is-missing share/static/js/swaggerui/swagger-ui-standalone-preset.js *
ngcp-panel source: source-is-missing share/static/js/swaggerui/swagger-ui.css *
ngcp-panel source: source-is-missing share/static/js/spectrum.min.js

@ -0,0 +1,39 @@
package NGCP::Panel::Controller::API::ResellerBrandings;
use parent qw/NGCP::Panel::Role::Entities NGCP::Panel::Role::API::ResellerBrandings/;
use Sipwise::Base;
use NGCP::Panel::Utils::Generic qw(:all);
sub allowed_methods{
return [qw/GET POST OPTIONS HEAD/];
}
__PACKAGE__->set_config({
POST => {
'ContentType' => ['multipart/form-data'],
'Uploads' => [qw/logo/],
},
allowed_roles => {
'Default' => [qw/admin reseller subscriberadmin subscriber/],
'POST' => [qw/admin reseller/],
}
});
# curl -v -X POST --user $USER --insecure -F logo=@path/to/logo.png json='{"reseller_id":1, "css":"<css code>", "csc_primary_color":"#AABBCC", "csc_secondary_color":"#AABBCC"}' https://localhost:4443/api/resellerbrandings/
sub api_description {
return 'Specifies a model to be set in <a href="#pbxdeviceconfigs">PbxDeviceConfigs</a>. Use a Content-Type "multipart/form-data", provide logo with the actual images, and an additional json part with the properties specified below, e.g.: <code>curl -X POST --user $USER -F logo=@/path/to/logo.png -F json=\'{"reseller_id":...}\' https://example.org:1443/api/resellerbrandings/</code> This resource is read-only to subscribes and subscriberadmins.';
};
sub create_item {
my ($self, $c, $resource, $form, $process_extras) = @_;
my $item = $c->model('DB')->resultset('reseller_brandings')->create($resource);
return $item;
}
1;
# vim: set tabstop=4 expandtab:

@ -0,0 +1,26 @@
package NGCP::Panel::Controller::API::ResellerBrandingsItem;
use Sipwise::Base;
use NGCP::Panel::Utils::Generic qw(:all);
use parent qw/NGCP::Panel::Role::EntitiesItem NGCP::Panel::Role::API::ResellerBrandings/;
__PACKAGE__->set_config({
PUT => {
'ContentType' => ['multipart/form-data'],
'Uploads' => [qw/logo/],
},
allowed_roles => {
'Default' => [qw/admin reseller subscriberadmin subscriber/],
'PUT' => [qw/admin reseller/],
'PATCH' => [qw/admin reseller/],
}
});
sub allowed_methods{
return [qw/GET OPTIONS HEAD PATCH PUT/];
}
1;
# vim: set tabstop=4 expandtab:

@ -27,6 +27,22 @@ has_field 'css' => (
element_class => [qw/ngcp-autoconf-area/],
);
has_field 'csc_color_primary' => (
type => 'Text',
required => 0,
label => 'CSC Primary Color',
maxlength => 45,
element_class => [qw/ngcp-csc-color-primary/],
);
has_field 'csc_color_secondary' => (
type => 'Text',
required => 0,
label => 'CSC Secondary Color',
maxlength => 45,
element_class => [qw/ngcp-csc-color-secondary/],
);
has_field 'save' => (
type => 'Submit',
value => 'Save',
@ -37,7 +53,7 @@ has_field 'save' => (
has_block 'fields' => (
tag => 'div',
class => [qw/modal-body/],
render_list => [qw/logo css/],
render_list => [qw/logo css csc_color_primary csc_color_secondary/],
);
has_block 'actions' => (

@ -0,0 +1,30 @@
package NGCP::Panel::Form::Reseller::BrandingAPI;
use HTML::FormHandler::Moose;
extends 'NGCP::Panel::Form::Reseller::Branding';
has_field 'reseller_id' => (
type => 'PosInteger',
required => 1,
element_attr => {
rel => ['tooltip'],
title => ['The reseller who owns the Branding.'],
},
);
has_block 'fields' => (
tag => 'div',
class => [qw/modal-body/],
render_list => [qw/reseller_id logo css csc_color_primary csc_color_secondary/],
);
sub update_fields {
my ($self) = @_;
my $c = $self->ctx;
return unless($c);
$self->field('logo')->inactive(1);
}
1;
# vim: set tabstop=4 expandtab:

@ -0,0 +1,155 @@
package NGCP::Panel::Role::API::ResellerBrandings;
use parent qw/NGCP::Panel::Role::API/;
use Sipwise::Base;
use NGCP::Panel::Utils::Generic qw(:all);
use HTTP::Status qw(:constants);
use NGCP::Panel::Form;
use boolean qw(true);
use JSON qw();
use File::Type;
sub item_name{
return 'resellerbrandings';
}
sub resource_name{
return 'resellerbrandings';
}
sub dispatch_path{
return '/api/resellerbrandings/';
}
sub relation{
return 'http://purl.org/sipwise/ngcp-api/#rel-resellerbrandings';
}
sub config_allowed_roles {
return {
'Default' => [qw/admin reseller subscriberadmin subscriber/],
#GET will use default
'POST' => [qw/admin reseller/],
'PUT' => [qw/admin reseller/],
'PATCH' => [qw/admin reseller/],
};
}
sub get_form {
my ($self, $c) = @_;
#use_fields_for_input_without_param
return (NGCP::Panel::Form::get("NGCP::Panel::Form::Reseller::BrandingAPI", $c));
}
sub _item_rs {
my ($self, $c) = @_;
my $item_rs = $c->model('DB')->resultset('reseller_brandings')->search(
{
'reseller.status' => { '!=' => 'terminated' }
},
{
join => 'reseller'
}
);
if ($c->user->roles eq "admin") {
} elsif ($c->user->roles eq "reseller") {
$item_rs = $item_rs->search({ reseller_id => $c->user->reseller_id });
} elsif ($c->user->roles eq "subscriberadmin" || $c->user->roles eq "subscriber") {
my $reseller_id = $c->user->contract->contact->reseller_id;
return unless $reseller_id;
$item_rs = $item_rs->search({
reseller_id => $reseller_id,
});
}
return $item_rs;
}
sub item_by_id {
my ($self, $c, $id) = @_;
return $self->item_rs($c)->search_rs({'reseller.id' => $id})->first;
}
sub resource_from_item {
my ($self, $c, $item) = @_;
my %resource = $item->get_inflated_columns;
delete $resource{logo};
my ($form) = $self->get_form($c);
return unless $self->validate_form(
c => $c,
form => $form,
resource => \%resource,
run => 0,
);
foreach my $field (qw/reseller_id id/){
$resource{$field} = int($item->$field // 0);
}
return \%resource;
}
sub process_form_resource{
my($self,$c, $item, $old_resource, $resource, $form, $process_extras) = @_;
my $reseller_id = delete $resource->{reseller_id};
if($c->user->roles eq "admin") {
} elsif($c->user->roles eq "reseller") {
$reseller_id = $c->user->reseller_id;
}
$resource->{reseller_id} = $reseller_id;
my $ft = File::Type->new();
if($resource->{logo}) {
my $image = delete $resource->{logo};
$resource->{logo} = $image->slurp;
$resource->{logo_image_type} = $ft->mime_type($resource->{logo});
}
return $resource;
}
sub check_resource{
my($self, $c, $item, $old_resource, $resource, $form, $process_extras) = @_;
my $schema = $c->model('DB');
my $reseller = $c->model('DB')->resultset('resellers')->find($resource->{reseller_id});
unless($reseller) {
$c->log->error("invalid reseller_id '".((defined $resource->{reseller_id})?$resource->{reseller_id} : "undefined")."', does not exist");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid reseller_id, does not exist");
return;
}
return 1;
}
sub check_duplicate{
my($self, $c, $item, $old_resource, $resource, $form, $process_extras) = @_;
my $schema = $c->model('DB');
my $existing_item = $c->model('DB')->resultset('reseller_brandings')->find({
reseller_id => $resource->{reseller_id},
});
if($existing_item && (!$item || $item->id != $existing_item->id)) {
$c->log->error("Branding already exists for reseller_id '$$resource{reseller_id}'");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Branding already exists for this reseller");
return;
}
return 1;
}
sub update_item_model {
my ($self, $c, $item, $old_resource, $resource, $form, $process_extras) = @_;
$item->update($resource);
return $item;
}
1;
# vim: set tabstop=4 expandtab:

@ -595,4 +595,15 @@ div.login {
display: none;
}
/* -------------
Reseller Bradnings
----------------*/
.color-box {
display: inline-block;
width: 50px;
border: 1px solid black;
border-radius: 5px;
}
/* vim: set tabstop=4 syntax=css expandtab: */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -46,6 +46,18 @@
[% branding.css %]
</pre>
</p>
<h3>[% c.loc('CSC Primary Color: ') %]
<div class="color-box" style="background-color: [% branding.csc_color_primary %]">
&nbsp;
</div>
<div style="display: inline-block;">[% branding.csc_color_primary %]</div>
</h3>
<h3>[% c.loc('CSC Secondary Color: ') %]
<div class="color-box" style="background-color: [% branding.csc_color_secondary %]">
&nbsp;
</div>
<div style="display: inline-block;">[% branding.csc_color_secondary %]</div>
</h3>
[% ELSE -%]
[% c.loc('No branding specified, using standard branding.') %]
[% END -%]
@ -62,6 +74,20 @@
modal_footer();
modal_script(m.close_target = close_target);
-%]
<script type="text/javascript" src="/js/spectrum.min.js"></script>
<link rel="stylesheet" type="text/css" href="/css/spectrum.min.css" />
<script>
$(document).ready(function() {
$('.ngcp-csc-color-primary').spectrum({
type: "component",
showInput: true
});
$('.ngcp-csc-color-secondary').spectrum({
type: "component",
showInput: true
});
});
</script>
[% END -%]
[% # vim: set tabstop=4 syntax=html expandtab: -%]

@ -359,6 +359,18 @@
[% branding.css %]
</pre>
</p>
<h3>[% c.loc('CSC Primary Color: ') %]
<div class="color-box" style="background-color: [% branding.csc_color_primary %]">
&nbsp;
</div>
<div style="display: inline-block;">[% branding.csc_color_primary %]</div>
</h3>
<h3>[% c.loc('CSC Secondary Color: ') %]
<div class="color-box" style="background-color: [% branding.csc_color_secondary %]">
&nbsp;
</div>
<div style="display: inline-block;">[% branding.csc_color_secondary %]</div>
</h3>
[% ELSE -%]
No branding specified, using standard branding.
[% END -%]
@ -500,6 +512,20 @@
modal_footer();
modal_script(m.close_target = close_target);
-%]
<script type="text/javascript" src="/js/spectrum.min.js"></script>
<link rel="stylesheet" type="text/css" href="/css/spectrum.min.css" />
<script>
$(document).ready(function() {
$('.ngcp-csc-color-primary').spectrum({
type: "component",
showInput: true
});
$('.ngcp-csc-color-secondary').spectrum({
type: "component",
showInput: true
});
});
</script>
[% END -%]
[% # vim: set tabstop=4 syntax=html expandtab: -%]

Loading…
Cancel
Save