From 27bdde4e3e10a26e8ee972d0c5071ce71ec6ff64 Mon Sep 17 00:00:00 2001
From: Kirill Solomko <ksolomko@sipwise.com>
Date: Fri, 21 Feb 2025 14:26:45 +0100
Subject: [PATCH] MT#62178 fix external_id, profile auto removal for subscriber
 roles

* fix 'subscriber' and 'subscriberadmin' roles using PATCH to cause
  external_id, and profile fields removed.
* remove profile_id field from the 'subscriber' and 'subscriberadmin'
  form

Change-Id: Id8bb068ca7fcac2c0c5954f2ed79e841d18ac398
(cherry picked from commit 97e457c92b5990ea6b6fc835a8f1852a040f5c9e)
---
 .../Panel/Controller/API/SubscribersItem.pm   |  5 +--
 .../Form/Subscriber/SubscriberSubAdminAPI.pm  | 10 ------
 lib/NGCP/Panel/Role/API/Subscribers.pm        | 31 ++++++++++++++-----
 3 files changed, 26 insertions(+), 20 deletions(-)

diff --git a/lib/NGCP/Panel/Controller/API/SubscribersItem.pm b/lib/NGCP/Panel/Controller/API/SubscribersItem.pm
index 8e0eb85248..12abdda795 100644
--- a/lib/NGCP/Panel/Controller/API/SubscribersItem.pm
+++ b/lib/NGCP/Panel/Controller/API/SubscribersItem.pm
@@ -134,14 +134,15 @@ sub PATCH :Allow {
         );
         last unless $json;
 
+        my $patch_mode = 1;
         my ($form) = $self->get_form($c);
-        my $old_resource = $self->resource_from_item($c, $subscriber, $form);
+        my $old_resource = $self->resource_from_item($c, $subscriber, $form, $patch_mode);
         $old_resource = clone($old_resource);
         my $resource = $self->apply_patch($c, $old_resource, $json);
         last unless $resource;
 
         my $update = 1;
-        my $r = $self->prepare_resource($c, $schema, $resource, $subscriber);
+        my $r = $self->prepare_resource($c, $schema, $resource, $subscriber, $patch_mode);
         last unless $r;
         $resource = $r->{resource};
 
diff --git a/lib/NGCP/Panel/Form/Subscriber/SubscriberSubAdminAPI.pm b/lib/NGCP/Panel/Form/Subscriber/SubscriberSubAdminAPI.pm
index b9796b49e9..898dc9f7e5 100644
--- a/lib/NGCP/Panel/Form/Subscriber/SubscriberSubAdminAPI.pm
+++ b/lib/NGCP/Panel/Form/Subscriber/SubscriberSubAdminAPI.pm
@@ -143,16 +143,6 @@ has_field 'customer_id' => (
     },
 );
 
-has_field 'profile' => (
-    type => '+NGCP::Panel::Field::SubscriberProfile',
-    label => 'Subscriber Profile',
-    validate_when_empty => 0,
-    element_attr => {
-        rel => ['tooltip'],
-        title => ['The profile defining the actual feature set for this subscriber.'],
-    },
-);
-
 has_field 'display_name' => (
     type => 'Text',
     label => 'Display Name',
diff --git a/lib/NGCP/Panel/Role/API/Subscribers.pm b/lib/NGCP/Panel/Role/API/Subscribers.pm
index 22acf1f1bb..8ad9729bbd 100644
--- a/lib/NGCP/Panel/Role/API/Subscribers.pm
+++ b/lib/NGCP/Panel/Role/API/Subscribers.pm
@@ -46,7 +46,7 @@ sub get_form {
 }
 
 sub resource_from_item {
-    my ($self, $c, $item, $form) = @_;
+    my ($self, $c, $item, $form, $patch_mode) = @_;
     my $pref;
 
     my $bill_resource = { $item->get_inflated_columns };
@@ -78,15 +78,26 @@ sub resource_from_item {
     }
     my $sippassword = $resource{password};
     my $webpassword = $resource{webpassword};
+
     if(!$form){
         ($form) = $self->get_form($c);
     }
+
+    # form validation during PATCH causes
+    # fields to be removed from the %resource
+    # and then apply_patch() removes the fields
+    # that were not a part the PATCH ops from
+    # the database, therefore a copy of the resource
+    # is validated instead, preserving the original one
+    # when $patch_mode is enabled
+    my %validate_resource = %resource;
     last unless $self->validate_form(
         c => $c,
-        resource => \%resource,
+        resource => $patch_mode ? \%validate_resource : \%resource,
         form => $form,
         run => 0,
     );
+
     $resource{_password} = $sippassword;
     $resource{_webpassword} = $webpassword;
 
@@ -192,10 +203,6 @@ sub resource_from_item {
             }
         }
     } else {
-        # fields we never want to see
-        foreach my $k(qw/profile_set_id external_id/) {
-            delete $resource{$k};
-        }
         delete $resource{'password'} if $c->user->roles eq 'subscriber';
 
         if ($c->user->roles eq "subscriberadmin") {
@@ -346,7 +353,7 @@ sub get_customer {
 }
 
 sub prepare_resource {
-    my ($self, $c, $schema, $resource, $item) = @_;
+    my ($self, $c, $schema, $resource, $item, $patch_mode) = @_;
 
     return NGCP::Panel::Utils::Subscriber::prepare_resource(
         c => $c,
@@ -360,9 +367,17 @@ sub prepare_resource {
         validate_code => sub {
             my ($r) = @_;
             my ($form) = $self->get_form($c);
+            # form validation during PATCH causes
+            # fields to be removed from the %resource
+            # and then apply_patch() removes the fields
+            # that were not a part the PATCH ops from
+            # the database, therefore a copy of the resource
+            # is validated instead, preserving the original one
+            # when $patch_mode is enabled
+            my %validate_resource = %{$r};
             return $self->validate_form(
                 c => $c,
-                resource => $r,
+                resource => $patch_mode ? \%validate_resource : $r,
                 form => $form,
             );
         },