diff --git a/appinfo/info.xml b/appinfo/info.xml index dc5aa25c5412921ea83de92fde0732915124b494..1bc21400d5ee6e0f95c1f8c80e49501197ca03ac 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -10,7 +10,7 @@ - 3.1.0 + 3.2.0 agpl Murena SAS EcloudAccounts @@ -20,7 +20,7 @@ - OCA\EcloudAccounts\Settings\Personal + OCA\EcloudAccounts\Settings\DeleteShopAccountSetting OCA\EcloudAccounts\Settings\BetaUserSetting OCA\EcloudAccounts\Settings\BetaSection diff --git a/appinfo/routes.php b/appinfo/routes.php index 761120a88011a120e8c3f65063a2d6e21b4865a1..aedd91313caeaa606ed4b823858eca51c1d482e6 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -6,9 +6,7 @@ return ['routes' => [ ['name' => 'user#set_mail_quota_usage', 'url' => '/api/set_mail_quota_usage', 'verb' => 'POST'], ['name' => 'shop_account#set_shop_email_post_delete', 'url' => '/shop-accounts/set_shop_email_post_delete', 'verb' => 'POST' ], ['name' => 'shop_account#set_shop_delete_preference', 'url' => '/shop-accounts/set_shop_delete_preference', 'verb' => 'POST' ], - ['name' => 'shop_account#get_order_info', 'url' => '/shop-accounts/order_info', 'verb' => 'GET'], - ['name' => 'shop_account#get_subscription_info', 'url' => '/shop-accounts/subscription_info', 'verb' => 'GET'], - ['name' => 'shop_account#get_shop_user', 'url' => '/shop-accounts/user', 'verb' => 'GET'], + ['name' => 'shop_account#get_shop_users', 'url' => '/shop-accounts/users', 'verb' => 'GET'], ['name' => 'shop_account#check_shop_email_post_delete', 'url' => '/shop-accounts/check_shop_email_post_delete', 'verb' => 'GET'], [ 'name' => 'user#preflighted_cors', 'url' => '/api/{path}', diff --git a/l10n/de.js b/l10n/de.js index d6e8e0518469951bd63dd2ae8a1ef74ee85fb424..46823807c0b0529486c65f7bea7209d478e71645 100644 --- a/l10n/de.js +++ b/l10n/de.js @@ -4,10 +4,11 @@ OC.L10N.register( "Email Address": "E-Mail Adresse", "Options": "Optionen", "We are going to proceed with your cloud account suppression.": "Wir werden mit der Löschung Ihres Cloud-Kontos fortfahren.", - "Check the box below if you also want to delete the associated shop account.": "Markieren Sie das Kästchen unten, wenn Sie auch das zugehörige Shop-Konto löschen möchten.", + "Check the box below if you also want to delete the associated shop account(s).": "Aktivieren Sie das folgende Kontrollkästchen, wenn Sie auch das/die zugehörige(n) Shop-Konto/Konten löschen möchten", "For your information you have %d order(s) in your account.": "Zu Ihrer Information: Sie haben %d Auftrag(e) in Ihrem Konto.", + "For your information you have %d order(s) in your accounts: ": "Zu Ihrer Information: Sie haben %d Auftrag(e) in Ihre Konten: ", "I also want to delete my shop account": "Ich möchte auch mein Shop-Konto löschen", - "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop. ": "Wenn Sie Ihr Shop-Konto behalten möchten, bestätigen oder ändern Sie bitte die E-Mail-Adresse unten. Diese E-Mail-Adresse wird Ihr neues Login für den Shop sein. ", + "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop.": "Wenn Sie Ihr Shop-Konto behalten möchten, bestätigen oder ändern Sie bitte die E-Mail-Adresse unten. Diese E-Mail-Adresse wird Ihr neues Login für den Shop sein.", "Error while setting shop delete preference": "Fehler beim Einstellen der Shop-Löschpräferenz", "Shop email cannot be same as this account's email.": "Die E-Mail von Murena.com kann nicht mit der E-Mail dieses Kontos übereinstimmen.", "Invalid Email Format.": "Ungültiges E-Mail-Format.", diff --git a/l10n/de.json b/l10n/de.json index f83d494937b378c68e37474ff8001f7b1074e996..b94ac70996e19245b316afeb864ec612ae964f0b 100644 --- a/l10n/de.json +++ b/l10n/de.json @@ -3,10 +3,11 @@ "Email Address": "E-Mail Adresse", "Options": "Optionen", "We are going to proceed with your cloud account suppression.": "Wir werden mit der Löschung Ihres Cloud-Kontos fortfahren.", - "Check the box below if you also want to delete the associated shop account.": "Markieren Sie das Kästchen unten, wenn Sie auch das zugehörige Shop-Konto löschen möchten.", + "Check the box below if you also want to delete the associated shop account(s).": "Aktivieren Sie das folgende Kontrollkästchen, wenn Sie auch das/die zugehörige(n) Shop-Konto/Konten löschen möchten", "For your information you have %d order(s) in your account.": "Zu Ihrer Information: Sie haben %d Auftrag(e) in Ihrem Konto.", + "For your information you have %d order(s) in your accounts: ": "Zu Ihrer Information: Sie haben %d Auftrag(e) in Ihre Konten: ", "I also want to delete my shop account": "Ich möchte auch mein Shop-Konto löschen", - "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop. ": "Wenn Sie Ihr Shop-Konto behalten möchten, bestätigen oder ändern Sie bitte die E-Mail-Adresse unten. Diese E-Mail-Adresse wird Ihr neues Login für den Shop sein. ", + "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop.": "Wenn Sie Ihr Shop-Konto behalten möchten, bestätigen oder ändern Sie bitte die E-Mail-Adresse unten. Diese E-Mail-Adresse wird Ihr neues Login für den Shop sein.", "Error while setting shop delete preference": "Fehler beim Einstellen der Shop-Löschpräferenz", "Shop email cannot be same as this account's email.": "Die E-Mail von Murena.com kann nicht mit der E-Mail dieses Kontos übereinstimmen.", "Invalid Email Format.": "Ungültiges E-Mail-Format.", diff --git a/l10n/en.js b/l10n/en.js index af35aee28d564748292cd9697ace472d49435fe5..bc284754685fa5b3591900c770a0c11c91665552 100644 --- a/l10n/en.js +++ b/l10n/en.js @@ -1,13 +1,16 @@ +/* eslint-disable quote-props */ +/* eslint-disable quotes */ OC.L10N.register( "ecloud-accounts", { "Email Address": "Email Address", "Options": "Options", "We are going to proceed with your cloud account suppression.": "We are going to proceed with your cloud account suppression.", - "Check the box below if you also want to delete the associated shop account.": "Check the box below if you also want to delete the associated shop account.", + "Check the box below if you also want to delete the associated shop account(s).": "Check the box below if you also want to delete the associated shop account(s).", "For your information you have %d order(s) in your account.": "For your information you have %d order(s) in your account.", + "For your information you have %d order(s) in your accounts: ": "For your information you have %d order(s) in your accounts: ", "I also want to delete my shop account": "I also want to delete my shop account", - "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop. ": "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop. ", + "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop.": "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop.", "Error while setting shop delete preference": "Error while setting shop delete preference", "Shop email cannot be same as this account's email.": "Murena.com email cannot be same as this account's email.", "Invalid Email Format.": "Invalid Email Format.", diff --git a/l10n/en.json b/l10n/en.json index ea45c32612cfcc89d904aae4ef6440b74c397cd2..bdcda7af86cadb8db63f08a1eea23a796363dd22 100644 --- a/l10n/en.json +++ b/l10n/en.json @@ -3,10 +3,11 @@ "Email Address": "Email Address", "Options": "Options", "We are going to proceed with your cloud account suppression.": "We are going to proceed with your cloud account suppression.", - "Check the box below if you also want to delete the associated shop account.": "Check the box below if you also want to delete the associated shop account.", + "Check the box below if you also want to delete the associated shop account(s).": "Check the box below if you also want to delete the associated shop account(s).", "For your information you have %d order(s) in your account.": "For your information you have %d order(s) in your account.", + "For your information you have %d order(s) in your accounts: ": "For your information you have %d order(s) in your accounts: ", "I also want to delete my shop account": "I also want to delete my shop account", - "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop. ": "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop. ", + "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop.": "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop.", "Error while setting shop delete preference": "Error while setting shop delete preference", "Shop email cannot be same as this account's email.": "Murena.com email cannot be same as this account's email.", "Invalid Email Format.": "Invalid Email Format.", diff --git a/l10n/es.js b/l10n/es.js index e241ca0be7d4b9af6191a2f13d38b70fe9be3990..713bffb6b47943bdb3fe6a9ba3078147e457b977 100644 --- a/l10n/es.js +++ b/l10n/es.js @@ -4,10 +4,11 @@ OC.L10N.register( "Email Address": "Correo electrónico", "Options": "Opciones", "We are going to proceed with your cloud account suppression.": "Vamos a proceder a la supresión de su cuenta en la nube.", - "Check the box below if you also want to delete the associated shop account.": "Marca la casilla de abajo si también quieres eliminar la cuenta de la tienda asociada.", + "Check the box below if you also want to delete the associated shop account(s).": "Marque la casilla siguiente si también desea eliminar la(s) cuenta(s) de la tienda asociada(s).", "For your information you have %d order(s) in your account.": "Para su información tiene %d orden(es) en su cuenta.", + "For your information you have %d order(s) in your accounts: ": "Para su información tiene %d orden(es) en sus cuentas: ", "I also want to delete my shop account": "También quiero borrar mi cuenta de la tienda", - "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop. ": "Si quieres mantener tu cuenta de la tienda, valida o modifica la dirección de correo electrónico que aparece a continuación. Esta dirección de correo electrónico se convertirá en su nuevo acceso a la tienda. ", + "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop.": "Si quieres mantener tu cuenta de la tienda, valida o modifica la dirección de correo electrónico que aparece a continuación. Esta dirección de correo electrónico se convertirá en su nuevo acceso a la tienda.", "Error while setting shop delete preference": "Error al configurar la preferencia de eliminación de la tienda", "Shop email cannot be same as this account's email.": "El correo electrónico de Murena.com no puede ser el mismo que el de esta cuenta.", "Invalid Email Format.": "Formato de correo electrónico no válido.", diff --git a/l10n/es.json b/l10n/es.json index b92ea24464341cd72c6ae781ea756a4fa681bee8..fc0959d3b69ec60265984a7d2bfe05800cb99480 100644 --- a/l10n/es.json +++ b/l10n/es.json @@ -3,10 +3,11 @@ "Email Address": "Correo electrónico", "Options": "Opciones", "We are going to proceed with your cloud account suppression.": "Vamos a proceder a la supresión de su cuenta en la nube. ", - "Check the box below if you also want to delete the associated shop account.": "Marca la casilla de abajo si también quieres eliminar la cuenta de la tienda asociada.", + "Check the box below if you also want to delete the associated shop account(s).": "Marque la casilla siguiente si también desea eliminar la(s) cuenta(s) de la tienda asociada(s).", "For your information you have %d order(s) in your account.": "Para su información tiene %d orden(es) en su cuenta.", + "For your information you have %d order(s) in your accounts: ": "Para su información tiene %d orden(es) en sus cuentas: ", "I also want to delete my shop account": "También quiero borrar mi cuenta de la tienda", - "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop. ": "Si quieres mantener tu cuenta de la tienda, valida o modifica la dirección de correo electrónico que aparece a continuación. Esta dirección de correo electrónico se convertirá en su nuevo acceso a la tienda. ", + "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop.": "Si quieres mantener tu cuenta de la tienda, valida o modifica la dirección de correo electrónico que aparece a continuación. Esta dirección de correo electrónico se convertirá en su nuevo acceso a la tienda.", "Error while setting shop delete preference": "Error al configurar la preferencia de eliminación de la tienda", "Shop email cannot be same as this account's email.": "El correo electrónico de Murena.com no puede ser el mismo que el de esta cuenta.", "Invalid Email Format.": "Formato de correo electrónico no válido.", diff --git a/l10n/fr.js b/l10n/fr.js index 16ef52565fd21640309734e860ce54f409ad8a80..11002b93d2fc29910ad7fbf29ff325971dd1539c 100644 --- a/l10n/fr.js +++ b/l10n/fr.js @@ -4,10 +4,11 @@ OC.L10N.register( "Email Address": "Adresse e-mail", "Options": "Options", "We are going to proceed with your cloud account suppression.": "Nous allons procéder à la suppression de votre compte cloud.", - "Check the box below if you also want to delete the associated shop account.": "Cochez la case ci-dessous si vous souhaitez également supprimer le compte boutique associé.", + "Check the box below if you also want to delete the associated shop account(s).": "Cochez la case ci-dessous si vous souhaitez également supprimer le(s) compte(s) boutique(s) associé(s).", "For your information you have %d order(s) in your account.": "Pour votre information, vous avez %d ordre(s) en votre compte.", - "I also want to delete my shop account": "I also want to delete my shop account", - "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop. ": "Si vous souhaitez conserver votre compte boutique, veuillez valider ou modifier l'adresse e-mail ci-dessous. Cette adresse email deviendra votre nouveau login pour la boutique. ", + "For your information you have %d order(s) in your accounts: ": "Pour votre information, vous avez %d ordre(s) en vos comptes: ", + "I also want to delete my shop account": "Je souhaite également supprimer mon compte boutique", + "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop.": "Si vous souhaitez conserver votre compte boutique, veuillez valider ou modifier l'adresse e-mail ci-dessous. Cette adresse email deviendra votre nouveau login pour la boutique.", "Error while setting shop delete preference": "Erreur lors de la configuration de la préférence de suppression de boutique", "Shop email cannot be same as this account's email.": "L'adresse électronique de Murena.com ne peut pas être la même que celle de ce compte.", "Invalid Email Format.": "Format d'email invalide.", diff --git a/l10n/fr.json b/l10n/fr.json index 963b412caf5612d39c86c2b4a4b1847fc470dec5..1a3e3ae4a6f6b88d19f67fd2bbe13e1ce6d43b11 100644 --- a/l10n/fr.json +++ b/l10n/fr.json @@ -3,10 +3,11 @@ "Email Address": "Adresse e-mail", "Options": "Options", "We are going to proceed with your cloud account suppression.": "Nous allons procéder à la suppression de votre compte cloud.", - "Check the box below if you also want to delete the associated shop account.": "Cochez la case ci-dessous si vous souhaitez également supprimer le compte boutique associé.", + "Check the box below if you also want to delete the associated shop account(s).": "Cochez la case ci-dessous si vous souhaitez également supprimer le(s) compte(s) boutique(s) associé(s).", "For your information you have %d order(s) in your account.": "Pour votre information, vous avez %d ordre(s) en votre compte.", - "I also want to delete my shop account": "I also want to delete my shop account", - "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop. ": "Si vous souhaitez conserver votre compte boutique, veuillez valider ou modifier l'adresse e-mail ci-dessous. Cette adresse email deviendra votre nouveau login pour la boutique. ", + "For your information you have %d order(s) in your accounts: ": "Pour votre information, vous avez %d ordre(s) en vos comptes: ", + "I also want to delete my shop account": "Je souhaite également supprimer mon compte boutique", + "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop.": "Si vous souhaitez conserver votre compte boutique, veuillez valider ou modifier l'adresse e-mail ci-dessous. Cette adresse email deviendra votre nouveau login pour la boutique.", "Error while setting shop delete preference": "Erreur lors de la configuration de la préférence de suppression de boutique", "Shop email cannot be same as this account's email.": "L'adresse électronique de Murena.com ne peut pas être la même que celle de ce compte.", "Invalid Email Format.": "Format d'email invalide.", diff --git a/l10n/it.js b/l10n/it.js index 209b447a58840acd6cfb24da05c5a2fbdada93be..12976c0976267010ba78dfe21f21c0f1e97db09a 100644 --- a/l10n/it.js +++ b/l10n/it.js @@ -4,10 +4,11 @@ OC.L10N.register( "Email Address": "Indirizzo e-mail", "Options": "Opzioni", "We are going to proceed with your cloud account suppression.": "Procederemo con la soppressione dell'account cloud.", - "Check the box below if you also want to delete the associated shop account.": "Selezionare la casella sottostante se si desidera eliminare anche l'account del negozio associato.", + "Check the box below if you also want to delete the associated shop account(s).": "Selezionare la casella sottostante se si desidera eliminare anche gli account del negozio associati.", "For your information you have %d order(s) in your account.": "Per vostra informazione, avete %d ordini in il tuo account.", + "For your information you have %d order(s) in your accounts: ": "Per vostra informazione, avete %d ordini in i vostri conti: ", "I also want to delete my shop account": "Voglio anche cancellare il mio account del negozio", - "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop. ": "Se volete mantenere il vostro account del negozio, convalidate o modificate l'indirizzo e-mail qui sotto. Questo indirizzo e-mail diventerà il vostro nuovo login al negozio. ", + "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop.": "Se volete mantenere il vostro account del negozio, convalidate o modificate l'indirizzo e-mail qui sotto. Questo indirizzo e-mail diventerà il vostro nuovo login al negozio.", "Error while setting shop delete preference": "Errore durante l'impostazione della preferenza di cancellazione del negozio", "Shop email cannot be same as this account's email.": "L'e-mail di Murena.com non può essere uguale a quella di questo account.", "Invalid Email Format.": "Formato email non valido.", diff --git a/l10n/it.json b/l10n/it.json index c5af4a7b30032ea8146fc320ea966ddf7fac36ea..2dc17b44b992016183dfbe332bd63199b0c76a2b 100644 --- a/l10n/it.json +++ b/l10n/it.json @@ -3,10 +3,11 @@ "Email Address": "Indirizzo e-mail", "Options": "Opzioni", "We are going to proceed with your cloud account suppression.": "Procederemo con la soppressione dell'account cloud. ", - "Check the box below if you also want to delete the associated shop account.": "Selezionare la casella sottostante se si desidera eliminare anche l'account del negozio associato.", + "Check the box below if you also want to delete the associated shop account(s).": "Selezionare la casella sottostante se si desidera eliminare anche gli account del negozio associati.", "For your information you have %d order(s) in your account.": "Per vostra informazione, avete %d ordini in il tuo account.", + "For your information you have %d order(s) in your accounts: ": "Per vostra informazione, avete %d ordini in i vostri conti: ", "I also want to delete my shop account": "Voglio anche cancellare il mio account del negozio", - "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop. ": "Se volete mantenere il vostro account del negozio, convalidate o modificate l'indirizzo e-mail qui sotto. Questo indirizzo e-mail diventerà il vostro nuovo login al negozio. ", + "If you want to keep your shop account please validate or modify the email address below. This email address will become your new login to the shop.": "Se volete mantenere il vostro account del negozio, convalidate o modificate l'indirizzo e-mail qui sotto. Questo indirizzo e-mail diventerà il vostro nuovo login al negozio.", "Error while setting shop delete preference": "Errore durante l'impostazione della preferenza di cancellazione del negozio", "Shop email cannot be same as this account's email.": "L'e-mail di Murena.com non può essere uguale a quella di questo account.", "Invalid Email Format.": "Formato email non valido.", diff --git a/lib/Controller/ShopAccountController.php b/lib/Controller/ShopAccountController.php index b53aa6f5fec97b93865c742f8ec7312c4bb1dbdd..2b9325358e1b5604f8ad9ed71646d5a6ea9e2a27 100644 --- a/lib/Controller/ShopAccountController.php +++ b/lib/Controller/ShopAccountController.php @@ -10,19 +10,14 @@ use OCP\IUserSession; use OCP\IRequest; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\DataResponse; -use OCP\AppFramework\Http; use OCP\ILogger; class ShopAccountController extends Controller { - private $shopAccountService; - private $userSession; + private ShopAccountService $shopAccountService; + private IUserSession $userSession; + + private ILogger $logger; - private $logger; - private const SUBSCRIPTION_STATUS_LIST = [ - 'pending', - 'active', - 'on-hold' - ]; public function __construct($appName, IRequest $request, IUserSession $userSession, ShopAccountService $shopAccountService, ILogger $logger) { parent::__construct($appName, $request); @@ -81,66 +76,19 @@ class ShopAccountController extends Controller { /** * @NoAdminRequired */ - public function getOrderInfo(int $userId) { - try { - if (!$userId) { - throw new Exception("Invalid user id"); - } - $data = ['order_count' => 0, 'my_orders_url' => $this->shopAccountService->getShopUrl() . '/my-account/orders']; - $orders = $this->shopAccountService->getOrders($userId); - $data['order_count'] = count($orders); - $response = new DataResponse(); - $response->setData($data); - return $response; - } catch (Exception $e) { - $this->logger->error('There was an issue querying order for user : ' . strval($userId)); - $this->logger->logException($e, ['app' => Application::APP_ID]); - return new DataResponse([], Http::STATUS_BAD_REQUEST); - } - } - - /** - * @NoAdminRequired - */ - public function getSubscriptionInfo(int $userId) { - try { - if (!$userId) { - throw new Exception("Invalid user id"); - } - $data = ['subscription_count' => 0]; - $subscriptions = $this->shopAccountService->getSubscriptions($userId, 'any'); - $total_subscriptions = 0; - foreach ($subscriptions as $subscription) { - if (in_array($subscription['status'], self::SUBSCRIPTION_STATUS_LIST)) { - $total_subscriptions++; - } - } - $data['subscription_count'] = $total_subscriptions; - $response = new DataResponse(); - $response->setData($data); - return $response; - } catch (Exception $e) { - $this->logger->error('There was an issue querying subscription for user : ' . strval($userId)); - $this->logger->logException($e, ['app' => Application::APP_ID]); - return new DataResponse([], Http::STATUS_BAD_REQUEST); - } - } - - /** - * @NoAdminRequired - */ - public function getShopUser() { + public function getShopUsers() { $response = new DataResponse(); $user = $this->userSession->getUser(); $email = $user->getEMailAddress(); - $shopUser = $this->shopAccountService->getUser($email); + $shopUsers = $this->shopAccountService->getUsers($email); - if (!$shopUser || !$this->shopAccountService->isUserOIDC($shopUser)) { + if (empty($shopUsers)) { $response->setStatus(404); return $response; } - $response->setData($shopUser); + + $response->setData($shopUsers); return $response; } } diff --git a/lib/Listeners/BeforeUserDeletedListener.php b/lib/Listeners/BeforeUserDeletedListener.php index 9b87f22a45dd35f97556194d84da2f66885696dc..c69120dfd609325b8623c05e6abcc4f6b87c95a6 100644 --- a/lib/Listeners/BeforeUserDeletedListener.php +++ b/lib/Listeners/BeforeUserDeletedListener.php @@ -60,14 +60,16 @@ class BeforeUserDeletedListener implements IEventListener { } $deleteShopAccount = $this->shopAccountService->getShopDeletePreference($uid); - $shopUser = $this->shopAccountService->getUser($email); - - if ($shopUser && $this->shopAccountService->isUserOIDC($shopUser)) { - if ($deleteShopAccount) { - $this->shopAccountService->deleteUser($shopUser['id']); - } else { - $newEmail = $this->shopAccountService->getShopEmailPostDeletePreference($uid); - $newEmail = $this->shopAccountService->updateUserEmailAndEmptyOIDC($shopUser['id'], $newEmail); + $shopUsers = $this->shopAccountService->getUsers($email); + + if (!empty($shopUsers)) { + foreach ($shopUsers as $shopUser) { + if ($deleteShopAccount) { + $this->shopAccountService->deleteUser($shopUser['shop_url'], $shopUser['id']); + } else { + $newEmail = $this->shopAccountService->getShopEmailPostDeletePreference($uid); + $newEmail = $this->shopAccountService->updateUserEmailAndEmptyOIDC($shopUser['shop_url'], $shopUser['id'], $newEmail); + } } } } diff --git a/lib/Service/ShopAccountService.php b/lib/Service/ShopAccountService.php index 113109b87ce7c76dd0fbc3fa672f235d7b304feb..2fa12a0b2b076194d2cffdfb086db15d2b89b3da 100644 --- a/lib/Service/ShopAccountService.php +++ b/lib/Service/ShopAccountService.php @@ -9,39 +9,45 @@ use OCP\ILogger; use OCA\EcloudAccounts\AppInfo\Application; class ShopAccountService { - private $config; - private $appName; - private $curl; - private $logger; + private IConfig $config; + private string $appName; + private CurlService $curl; + private ILogger $logger; + private array $shops = []; + + private const OIDC_USERS_ENDPOINT = '/wp-json/openid-connect-generic/users/get_by_email'; + private const USERS_ENDPOINT = '/wp-json/wp/v2/users'; + private const MY_ORDERS_URL = '/my-account/orders'; + private const MULTISITE_KEY = 'is_multisite'; + private const MULTISITE_DELETE_USERS_ENDPOINT = '/wp-json/wp/v2/multisite/users'; public function __construct($appName, IConfig $config, CurlService $curlService, ILogger $logger) { $this->config = $config; $this->appName = $appName; - $shopUsername = $this->config->getSystemValue('murena_shop_username'); - $shopPassword = $this->config->getSystemValue('murena_shop_password'); - $this->shopUrl = $this->config->getSystemValue('murena_shop_url', ''); - $this->shopReassignUserId = $this->config->getSystemValue('murena_shop_reassign_user_id'); - + $shops = $this->config->getSystemValue('murena_shops', []); + foreach ($shops as $shop) { + if (!isset($shop[self::MULTISITE_KEY])) { + $shop[self::MULTISITE_KEY] = false; + } + $this->shops[$shop['url']] = $shop; + } - $this->shopUserUrl = $this->shopUrl . "/wp-json/wp/v2/users"; - $this->shopOrdersUrl = $this->shopUrl . "/wp-json/wc/v3/orders"; - $this->subscriptionUrl = $this->shopUrl . "/wp-json/wc/v3/subscriptions"; - $this->shopCredentials = base64_encode($shopUsername . ":" . $shopPassword); $this->curl = $curlService; $this->logger = $logger; } - public function getShopUrl() { - return $this->shopUrl; - } - public function setShopDeletePreference($userId, bool $delete) { $this->config->setUserValue($userId, $this->appName, 'delete_shop_account', intval($delete)); } public function shopEmailExists(string $shopEmail) : bool { - return !empty($this->getUser($shopEmail)); + foreach ($this->shops as $shop) { + if (!empty($this->getUser($shop, $shopEmail))) { + return true; + } + } + return false; } public function validateShopEmailPostDelete(string $shopEmailPostDelete, string $cloudEmail) : void { @@ -70,36 +76,51 @@ class ShopAccountService { return $this->config->getUserValue($userId, $this->appName, 'shop_email_post_delete', $recoveryEmail); } - public function getOrders(int $userId): ?array { - return $this->callShopAPI($this->shopOrdersUrl, 'GET', ['customer' => $userId]); - } - - public function getUsers(string $searchTerm): ?array { + public function getUsers(string $email): ?array { try { - return $this->callShopAPI($this->shopUserUrl, 'GET', ['search' => $searchTerm]); + $users = []; + foreach ($this->shops as $shop) { + $user = $this->getUser($shop, $email); + if (empty($user)) { + continue; + } + $users[] = $user; + } + + return $users; } catch (Exception $e) { - $this->logger->error('There was an issue querying shop for users'); $this->logger->logException($e, ['app' => Application::APP_ID]); } } - public function getUser(string $email) : ?array { - $users = $this->getUsers($email); - if (empty($users)) { + public function getUser(array $shop, string $email) : ?array { + $user = $this->callShopAPI($shop, self::OIDC_USERS_ENDPOINT, 'GET', ['email' => $email]); + if (empty($user)) { return null; } - return $users[0]; + $user['shop_url'] = $shop['url']; + $user['my_orders_url'] = $shop['url'] . self::MY_ORDERS_URL; + + return $user; } - public function deleteUser(int $userId) : void { + public function deleteUser(string $shopUrl, int $userId) : void { + $shop = $this->shops[$shopUrl]; + + $deleteEndpoint = self::USERS_ENDPOINT; + if ($shop[self::MULTISITE_KEY]) { + $deleteEndpoint = self::MULTISITE_DELETE_USERS_ENDPOINT; + } + + $deleteEndpoint = $deleteEndpoint . '/' . strval($userId); + $params = [ 'force' => true, - 'reassign' => $this->shopReassignUserId + 'reassign' => $shop['reassign_user_id'] ]; - $deleteUrl = $this->shopUserUrl . '/' . strval($userId); try { - $answer = $this->callShopAPI($deleteUrl, 'DELETE', $params); + $answer = $this->callShopAPI($shop, $deleteEndpoint, 'DELETE', $params); if (!$answer['deleted']) { throw new Exception('Unknown error while deleting!'); @@ -110,8 +131,9 @@ class ShopAccountService { } } - public function updateUserEmailAndEmptyOIDC(int $userId, string $email) : void { - $updateUrl = $this->shopUserUrl . '/' . strval($userId); + public function updateUserEmailAndEmptyOIDC(string $shopUrl, int $userId, string $email) : void { + $shop = $this->shops[$shopUrl]; + $updateEndpoint = self::USERS_ENDPOINT . '/' . strval($userId); $params = [ 'email' => $email, @@ -119,7 +141,7 @@ class ShopAccountService { ]; try { - $answer = $this->callShopAPI($updateUrl, 'POST', $params); + $answer = $this->callShopAPI($shop, $updateEndpoint, 'POST', $params); if ($answer['email'] !== $email) { throw new Exception('Unknown error while updating!'); @@ -130,26 +152,27 @@ class ShopAccountService { } } - private function callShopAPI(string $url, string $method, array $data = []) { - if (empty($this->shopUrl)) { + private function callShopAPI(array $shop, string $endpoint, string $method, array $data = []) { + if (empty($shop['url'])) { return []; } + $shopCredentials = base64_encode($shop['username'] . ':' . $shop['password']); $headers = [ "cache-control: no-cache", "content-type: application/json", - "Authorization: Basic " . $this->shopCredentials + "Authorization: Basic " . $shopCredentials ]; if ($method === 'GET') { - $answer = $this->curl->get($url, $data, $headers); + $answer = $this->curl->get($shop['url'] . $endpoint, $data, $headers); } if ($method === 'DELETE') { - $answer = $this->curl->delete($url, $data, $headers); + $answer = $this->curl->delete($shop['url'] . $endpoint, $data, $headers); } if ($method === 'POST') { - $answer = $this->curl->post($url, json_encode($data), $headers); + $answer = $this->curl->post($shop['url'] . $endpoint, json_encode($data), $headers); } $answer = json_decode($answer, true); @@ -159,12 +182,4 @@ class ShopAccountService { return $answer; } - - public function isUserOIDC(array $user) { - return !empty($user['openid-connect-generic-last-user-claim']); - } - - public function getSubscriptions(int $userId, string $status): ?array { - return $this->callShopAPI($this->subscriptionUrl, 'GET', ['customer' => $userId , 'status' => $status]); - } } diff --git a/lib/Settings/Personal.php b/lib/Settings/DeleteShopAccountSetting.php similarity index 75% rename from lib/Settings/Personal.php rename to lib/Settings/DeleteShopAccountSetting.php index 2e694e98fbf20e89421ec8748922bd024e8848db..c79416a7668914bc754fd9eea4a4d4f624bcec67 100644 --- a/lib/Settings/Personal.php +++ b/lib/Settings/DeleteShopAccountSetting.php @@ -4,15 +4,13 @@ namespace OCA\EcloudAccounts\Settings; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Services\IInitialState; -use OCP\IGroupManager; use OCP\IUserSession; use OCP\Settings\ISettings; use OCP\Util; use OCA\EcloudAccounts\Service\ShopAccountService; use OCP\App\IAppManager; -use OCP\IUserManager; -class Personal implements ISettings { +class DeleteShopAccountSetting implements ISettings { private const DROP_ACCOUNT_APP_ID = 'drop_account'; /** @var IUserSession */ private $userSession; @@ -27,21 +25,15 @@ class Personal implements ISettings { private $appManager; - private IGroupManager $groupManager; - - private IUserManager $userManager; - /** @var Util */ protected $util; - public function __construct($appName, IUserSession $userSession, IInitialState $initialState, ShopAccountService $shopAccountService, IAppManager $appManager, IGroupManager $groupManager, IUserManager $userManager, Util $util) { + public function __construct($appName, IUserSession $userSession, IInitialState $initialState, ShopAccountService $shopAccountService, IAppManager $appManager, Util $util) { $this->userSession = $userSession; $this->initialState = $initialState; $this->appName = $appName; $this->shopAccountService = $shopAccountService; $this->appManager = $appManager; - $this->userManager = $userManager; - $this->groupManager = $groupManager; $this->util = $util; } @@ -52,10 +44,7 @@ class Personal implements ISettings { public function getForm(): TemplateResponse { $user = $this->userSession->getUser(); if ($user) { - $onlyUser = $this->userManager->countUsers() < 2; - $adminGroup = $this->groupManager->get('admin'); - $onlyAdmin = $adminGroup && $adminGroup->count() < 2 && $this->groupManager->isAdmin($user->getUID()); - $this->util->addScript($this->appName, $this->appName.'-personal-settings'); + $this->util->addScript($this->appName, $this->appName.'-delete-shop-account-setting'); $this->util->addScript($this->appName, $this->appName.'-delete-account-listeners'); $deleteShopAccount = $this->shopAccountService->getShopDeletePreference($user->getUID()); $shopEmailPostDelete = $this->shopAccountService->getShopEmailPostDeletePreference($user->getUID()); @@ -63,8 +52,6 @@ class Personal implements ISettings { $this->initialState->provideInitialState('email', $user->getEMailAddress()); $this->initialState->provideInitialState('delete_shop_account', $deleteShopAccount); $this->initialState->provideInitialState('shop_email_post_delete', $shopEmailPostDelete); - $this->initialState->provideInitialState('only_user', $onlyUser); - $this->initialState->provideInitialState('only_admin', $onlyAdmin); } return new TemplateResponse($this->appName, 'personal'); diff --git a/src/PersonalSettings.vue b/src/DeleteShopAccountSetting.vue similarity index 55% rename from src/PersonalSettings.vue rename to src/DeleteShopAccountSetting.vue index 69ad36f9764eb577c2b50a1422ff26f8dcca0660..63bd381863ac8dfb575fc642598d452265e7b386 100644 --- a/src/PersonalSettings.vue +++ b/src/DeleteShopAccountSetting.vue @@ -1,23 +1,26 @@ @@ -82,55 +69,48 @@ import Axios from '@nextcloud/axios' import { generateUrl } from '@nextcloud/router' import { showError } from '@nextcloud/dialogs' +const APPLICATION_NAME = 'ecloud-accounts' + export default { - name: 'PersonalSettings', + name: 'DeleteShopAccountSetting', components: { SettingsSection, }, data() { return { - shopUserExists: false, - shopUser: {}, - deleteShopAccount: false, - shopEmailPostDelete: '', - shopEmailDefault: '', - appName: 'ecloud-accounts', - userEmail: '', - onlyAdmin: false, - onlyUser: false, - orderCount: 0, - subscriptionCount: 0, - ordersDescription: this.t('ecloud-accounts', "For your information you have %d order(s) in your account."), - subscriptionDescription: this.t('ecloud-accounts', 'A subscription is active in this account. Please cancel it or let it expire before deleting your account.'), - loading: true, + shopUsers: [], + deleteShopAccount: loadState(APPLICATION_NAME, 'delete_shop_account'), + shopEmailPostDelete: loadState(APPLICATION_NAME, 'shop_email_post_delete'), + appName: APPLICATION_NAME, + userEmail: loadState(APPLICATION_NAME, 'email'), showError: false, allowDelete: true, + ordersDescription: '' } }, - created() { - try { - this.onlyUser = loadState(this.appName, 'only_user') - this.onlyAdmin = loadState(this.appName, 'only_admin') - this.deleteShopAccount = loadState(this.appName, 'delete_shop_account') - this.shopEmailPostDelete = loadState(this.appName, 'shop_email_post_delete') - this.shopEmailDefault = loadState(this.appName, 'shop_email_post_delete') - this.userEmail = loadState(this.appName, 'email') - this.getShopUser().then(() => { - if (this.shopUserExists) { - this.getOrdersInfo() - this.getSubscriptionInfo() - } else { - this.disableOrEnableDeleteAccount() + computed: { + hasActiveSubscription() { + for (let index = 0; index < this.shopUsers.length; index++) { + if (this.shopUsers[index].has_active_subscription) { + return true } - - }) - } catch (e) { - console.error('Error fetching initial state', e) + } + return false + }, + orderCount() { + return this.shopUsers.reduce((accumulator, user) => { + return accumulator + user.order_count + }, 0) } }, + mounted() { + this.getShopUsers() + }, methods: { async disableOrEnableDeleteAccount() { - if (this.shopUserExists && !this.deleteShopAccount) { + if (!this.allowDelete || this.hasActiveSubscription) { + this.disableDeleteAccountEvent() + } else if (this.shopUsers.length > 0 && !this.deleteShopAccount) { this.disableDeleteAccountEvent() const status = await this.checkShopEmailPostDelete() if (status === 200) { @@ -159,60 +139,40 @@ export default { return err.response.status } }, - async getShopUser() { - try { - const url = generateUrl( - `/apps/${this.appName}/shop-accounts/user` - ) - const { status, data } = await Axios.get(url) - if (status === 200) { - this.shopUserExists = true - this.shopUser = data - } - if (status === 400) { - this.enableDeleteAccountEvent() - } - } catch (e) { + setOrderDescription() { + if (this.shopUsers.length === 1) { + const ordersDescription = this.t(APPLICATION_NAME, "For your information you have %d order(s) in your account.") + const myOrdersUrl = this.shopUsers[0].my_orders_url + this.ordersDescription = ordersDescription.replace('%d', this.orderCount).replace('%s', myOrdersUrl) + } else if (this.shopUsers.length >= 1) { + let ordersDescription = this.t(APPLICATION_NAME, 'For your information you have %d order(s) in your accounts: ') + + ordersDescription = ordersDescription.replace('%d', this.orderCount) + + const links = this.shopUsers.map((user, index) => { + return `[${index}]` + }) + this.ordersDescription = ordersDescription + links.join(' ') } }, - async getOrdersInfo() { + async getShopUsers() { try { const url = generateUrl( - `/apps/${this.appName}/shop-accounts/order_info?userId=${this.shopUser.id}` + `/apps/${this.appName}/shop-accounts/users` ) - const { status, data } = await Axios.get(url) - if (status === 200) { - this.orderCount = data.order_count - if (this.orderCount) { - this.ordersDescription = this.ordersDescription.replace('%d', this.orderCount).replace('%s', data.my_orders_url) - } - } - this.loading = false + const { data } = await Axios.get(url) + this.shopUsers = data + this.setOrderDescription() } catch (e) { - this.loading = false - } - }, - async getSubscriptionInfo() { - try { - const url = generateUrl( - `/apps/${this.appName}/shop-accounts/subscription_info?userId=${this.shopUser.id}` - ) - const { status, data } = await Axios.get(url) - if (status === 200) { - this.subscriptionCount = data.subscription_count - if (this.subscriptionCount > 0) { - this.disableDeleteAccountEvent() - } + if (e.response.status !== 404) { + this.disableDeleteAccountEvent() + showError( + t(APPLICATION_NAME, 'Temporary error contacting murena.com; please try again later!') + ) + this.allowDelete = false } - this.loading = false - } catch (e) { - this.disableDeleteAccountEvent() - showError( - t('ecloud-accounts', 'Temporary error contacting murena.com; please try again later!') - ) - this.loading = false - this.allowDelete = false } + this.disableOrEnableDeleteAccount() }, async updateDeleteShopPreference() { await this.disableOrEnableDeleteAccount() @@ -225,12 +185,12 @@ export default { }) if (status !== 200) { showError( - t('ecloud-accounts', 'Error while setting shop delete preference') + t(APPLICATION_NAME, 'Error while setting shop delete preference') ) } } catch (e) { showError( - t('ecloud-accounts', 'Error while setting shop delete preference') + t(APPLICATION_NAME, 'Error while setting shop delete preference') ) } }, @@ -254,7 +214,7 @@ export default { if (this.shopEmailPostDelete === this.userEmail) { showError( t( - 'ecloud-accounts', + APPLICATION_NAME, "Murena.com email cannot be same as this account's email." ) ) @@ -264,7 +224,7 @@ export default { this.disableDeleteAccountEvent() showError( t( - 'ecloud-accounts', + APPLICATION_NAME, data.message ) ) diff --git a/src/delete-account-listeners.js b/src/delete-account-listeners.js index 6710f7ffb1a6cb2a0cff32bc1155db3aa49a0c1b..a8a190b83c9493afcb9b2760df29a3b2d42a4fb1 100644 --- a/src/delete-account-listeners.js +++ b/src/delete-account-listeners.js @@ -1,17 +1,19 @@ document.addEventListener('DOMContentLoaded', function() { + const checkboxSelector = '#delete-account-settings .checkbox-radio-switch__input' + const buttonSelector = '#delete-account-settings .delete-button-wrapper .button-vue' // Disable initially - document.getElementById('drop_account_confirm').disabled = true - document.getElementById('deleteaccount').disabled = true + document.querySelector(checkboxSelector).disabled = true + document.querySelector(buttonSelector).disabled = true const elem = document.getElementById('body-settings') elem.addEventListener('disable-delete-account', function() { - document.getElementById('deleteaccount').disabled = true - document.getElementById('drop_account_confirm').disabled = true + document.querySelector(checkboxSelector).disabled = true + document.querySelector(buttonSelector).disabled = true }) elem.addEventListener('enable-delete-account', function() { - document.getElementById('drop_account_confirm').disabled = false - const enableDeleteAccount = document.getElementById('drop_account_confirm').checked - document.getElementById('deleteaccount').disabled = !enableDeleteAccount + document.querySelector(checkboxSelector).disabled = false + const enableDeleteAccount = document.querySelector(checkboxSelector).checked + document.querySelector(buttonSelector).disabled = !enableDeleteAccount }) }) diff --git a/src/personal.js b/src/delete-shop-account-setting.js similarity index 69% rename from src/personal.js rename to src/delete-shop-account-setting.js index ad8127b06dc7209c7e76a4d158b16ca4332333c8..4ab00df513b1b2bbc41605a2e6a1346f3d1529df 100644 --- a/src/personal.js +++ b/src/delete-shop-account-setting.js @@ -1,6 +1,6 @@ import Vue from 'vue' import './common.js' -import PersonalSettings from './PersonalSettings.vue' +import PersonalSettings from './DeleteShopAccountSetting.vue' export default new Vue({ el: '#ecloud-accounts-settings', diff --git a/webpack.config.js b/webpack.config.js index ea2fb2f24f4bfa34237c2e5730ccd414046f241a..b2b5fbb06e3dab6d263b633238ec3df4ac9b523d 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -6,7 +6,7 @@ const path = require('path') module.exports = { ...webpackConfig, entry: { - 'personal-settings': path.join(__dirname, 'src/personal.js'), + 'delete-shop-account-setting': path.join(__dirname, 'src/delete-shop-account-setting.js'), 'delete-account-listeners': path.join(__dirname, 'src/delete-account-listeners.js'), 'beta-user-setting': path.join(__dirname, 'src/beta-user-setting.js'), },