From 8aa535447e45963f91f2d31cf65c84124ff834b8 Mon Sep 17 00:00:00 2001 From: Maksym Sadovnychyy Date: Sat, 6 Jul 2024 00:07:51 +0200 Subject: [PATCH] (feature): account patch operations init and webapi cleanup --- src/ClientApp/app/page.tsx | 33 +-- src/ClientApp/app/register/page.tsx | 4 +- src/ClientApp/controls/customSelect.tsx | 31 +- src/ClientApp/entities/CacheAccount.ts | 28 ++ .../account/requests/PatchAccountRequest.ts | 6 +- .../account/requests/PatchContactsRequest.ts | 5 - .../account/requests/PatchHostnameRequest.ts | 6 + .../requests}/PostAccountRequest.ts | 0 .../account/requests/PostContactsRequest.ts | 3 - .../account/requests/PutAccountRequest.ts | 4 - .../account/requests/PutContactsRequest.ts | 3 - .../account/responses/GetAccountResponse.ts | 26 +- .../account/responses/GetContactsResponse.ts | 3 - ...nameResponse.ts => GetHostnameResponse.ts} | 2 +- .../account/responses/GetHostnamesResponse.ts | 5 - src/ClientApp/partials/accoutEdit.tsx | 170 +++++------ src/ClientApp/services/HttpService.tsx | 49 ++-- .../Entities/LetsEncrypt/RegistrationCache.cs | 5 +- .../Controllers/AccountController.cs | 84 ------ .../Services/AccoutService.cs | 271 ++++++------------ .../Services/CertsFlowService.cs | 34 +++ .../Account/Requests/PatchAccountRequest.cs | 20 +- .../Requests/PatchContactsRequest - Copy.cs | 12 - .../Account/Requests/PatchHostnameRequest.cs | 9 + .../Account/Requests/PatchHostnamesRequest.cs | 12 - .../Account/Requests/PostAccountRequest.cs | 33 ++- .../Account/Requests/PostContactsRequest.cs | 19 -- .../Account/Requests/PostHostnamesRequest.cs | 17 -- .../Account/Requests/PutAccountRequest.cs | 21 -- .../Account/Requests/PutContactsRequest.cs | 15 - .../Account/Requests/PutHostnamesRequest.cs | 17 -- .../Account/Responses/GetAccountResponse.cs | 2 +- .../Account/Responses/GetContactsResponse.cs | 11 - ...nameResponse.cs => GetHostnameResponse.cs} | 2 +- .../Account/Responses/GetHostnamesResponse.cs | 12 - 35 files changed, 377 insertions(+), 597 deletions(-) delete mode 100644 src/ClientApp/models/letsEncryptServer/account/requests/PatchContactsRequest.ts create mode 100644 src/ClientApp/models/letsEncryptServer/account/requests/PatchHostnameRequest.ts rename src/ClientApp/models/letsEncryptServer/{certsFlow => account/requests}/PostAccountRequest.ts (100%) delete mode 100644 src/ClientApp/models/letsEncryptServer/account/requests/PostContactsRequest.ts delete mode 100644 src/ClientApp/models/letsEncryptServer/account/requests/PutAccountRequest.ts delete mode 100644 src/ClientApp/models/letsEncryptServer/account/requests/PutContactsRequest.ts delete mode 100644 src/ClientApp/models/letsEncryptServer/account/responses/GetContactsResponse.ts rename src/ClientApp/models/letsEncryptServer/account/responses/{HostnameResponse.ts => GetHostnameResponse.ts} (69%) delete mode 100644 src/ClientApp/models/letsEncryptServer/account/responses/GetHostnamesResponse.ts delete mode 100644 src/Models/LetsEncryptServer/Account/Requests/PatchContactsRequest - Copy.cs create mode 100644 src/Models/LetsEncryptServer/Account/Requests/PatchHostnameRequest.cs delete mode 100644 src/Models/LetsEncryptServer/Account/Requests/PatchHostnamesRequest.cs delete mode 100644 src/Models/LetsEncryptServer/Account/Requests/PostContactsRequest.cs delete mode 100644 src/Models/LetsEncryptServer/Account/Requests/PostHostnamesRequest.cs delete mode 100644 src/Models/LetsEncryptServer/Account/Requests/PutAccountRequest.cs delete mode 100644 src/Models/LetsEncryptServer/Account/Requests/PutContactsRequest.cs delete mode 100644 src/Models/LetsEncryptServer/Account/Requests/PutHostnamesRequest.cs delete mode 100644 src/Models/LetsEncryptServer/Account/Responses/GetContactsResponse.cs rename src/Models/LetsEncryptServer/Account/Responses/{HostnameResponse.cs => GetHostnameResponse.cs} (90%) delete mode 100644 src/Models/LetsEncryptServer/Account/Responses/GetHostnamesResponse.cs diff --git a/src/ClientApp/app/page.tsx b/src/ClientApp/app/page.tsx index 7560b6d..fd3904d 100644 --- a/src/ClientApp/app/page.tsx +++ b/src/ClientApp/app/page.tsx @@ -1,7 +1,7 @@ 'use client' import { ApiRoutes, GetApiRoute } from '@/ApiRoutes' -import { httpService } from '@/services/httpService' +import { httpService } from '@/services/HttpService' import { FormEvent, useEffect, useRef, useState } from 'react' import { CustomButton, @@ -10,7 +10,10 @@ import { CustomInput, CustomRadioGroup } from '@/controls' -import { GetAccountResponse } from '@/models/letsEncryptServer/account/responses/GetAccountResponse' +import { + GetAccountResponse, + toCacheAccount +} from '@/models/letsEncryptServer/account/responses/GetAccountResponse' import { deepCopy, enumToArray } from '../functions' import { CacheAccount } from '@/entities/CacheAccount' import { ChallengeTypes } from '@/entities/ChallengeTypes' @@ -42,22 +45,7 @@ export default function Page() { if (!gatAccountsResult.isSuccess) return gatAccountsResult.data?.forEach((account) => { - newAccounts.push({ - accountId: account.accountId, - isDisabled: account.isDisabled, - description: account.description, - contacts: account.contacts.map((contact) => contact), - challengeType: account.challengeType, - hostnames: - account.hostnames?.map((hostname) => ({ - hostname: hostname.hostname, - expires: new Date(hostname.expires), - isUpcomingExpire: hostname.isUpcomingExpire, - isDisabled: hostname.isDisabled - })) ?? [], - isStaging: account.isStaging, - isEditMode: false - }) + newAccounts.push(toCacheAccount(account)) }) setAccounts(newAccounts) @@ -144,10 +132,6 @@ export default function Page() { title="Challenge Type" enumType={ChallengeTypes} selectedValue={account.challengeType} - onChange={(option) => - //handleChallengeTypeChange(account.accountId, option) - console.log('') - } disabled={true} /> @@ -206,9 +190,12 @@ export default function Page() { {editingAccount && ( setEditingAccount(null)} onDelete={deleteAccount} + onSubmit={(account) => { + setEditingAccount(null) + handleAccountUpdate(account) + }} /> )} diff --git a/src/ClientApp/app/register/page.tsx b/src/ClientApp/app/register/page.tsx index d6c1183..3955eb8 100644 --- a/src/ClientApp/app/register/page.tsx +++ b/src/ClientApp/app/register/page.tsx @@ -18,12 +18,12 @@ import { deepCopy } from '../../functions' import { PostAccountRequest, validatePostAccountRequest -} from '@/models/letsEncryptServer/certsFlow/PostAccountRequest' +} from '@/models/letsEncryptServer/account/requests/PostAccountRequest' import { useAppDispatch } from '@/redux/store' import { showToast } from '@/redux/slices/toastSlice' import { ChallengeTypes } from '@/entities/ChallengeTypes' import { GetAccountResponse } from '@/models/letsEncryptServer/account/responses/GetAccountResponse' -import { httpService } from '@/services/httpService' +import { httpService } from '@/services/HttpService' import { ApiRoutes, GetApiRoute } from '@/ApiRoutes' import { PageContainer } from '@/components/pageContainer' diff --git a/src/ClientApp/controls/customSelect.tsx b/src/ClientApp/controls/customSelect.tsx index ac8d782..34c0e9f 100644 --- a/src/ClientApp/controls/customSelect.tsx +++ b/src/ClientApp/controls/customSelect.tsx @@ -71,27 +71,41 @@ const CustomSelect: React.FC = ({ return (
- {title && } + {title && }
- {selectedOption ? selectedOption.label : 'Select an option'} + + {selectedOption ? selectedOption.label : 'Select an option'} + + {isOpen ? ( - + ) : ( - + )}
+ {isOpen && ( -
    +
      {options.map((option) => (
    • handleOptionClick(option)} > {option.label} @@ -100,6 +114,7 @@ const CustomSelect: React.FC = ({
    )}
+ {error && (

{error}

)} diff --git a/src/ClientApp/entities/CacheAccount.ts b/src/ClientApp/entities/CacheAccount.ts index e11a036..9afb78c 100644 --- a/src/ClientApp/entities/CacheAccount.ts +++ b/src/ClientApp/entities/CacheAccount.ts @@ -1,4 +1,6 @@ +import { PatchOperation } from '@/models/PatchOperation' import { CacheAccountHostname } from './CacheAccountHostname' +import { PatchAccountRequest } from '@/models/letsEncryptServer/account/requests/PatchAccountRequest' export interface CacheAccount { accountId: string @@ -10,3 +12,29 @@ export interface CacheAccount { isEditMode: boolean isStaging: boolean } + +const toPatchAccountRequest = (account: CacheAccount): PatchAccountRequest => { + return { + description: { op: PatchOperation.None, value: account.description }, + isDisabled: { op: PatchOperation.None, value: account.isDisabled }, + contacts: account.contacts.map((contact, index) => ({ + index: index, + op: PatchOperation.None, + value: contact + })), + hostnames: account.hostnames?.map((hostname, index) => ({ + hostname: { + index: index, + op: PatchOperation.None, + value: hostname.hostname + }, + isDisabled: { + index: index, + op: PatchOperation.None, + value: hostname.isDisabled + } + })) + } +} + +export { toPatchAccountRequest } diff --git a/src/ClientApp/models/letsEncryptServer/account/requests/PatchAccountRequest.ts b/src/ClientApp/models/letsEncryptServer/account/requests/PatchAccountRequest.ts index cf18b06..de65dc3 100644 --- a/src/ClientApp/models/letsEncryptServer/account/requests/PatchAccountRequest.ts +++ b/src/ClientApp/models/letsEncryptServer/account/requests/PatchAccountRequest.ts @@ -1,9 +1,5 @@ import { PatchAction } from '@/models/PatchAction' - -export interface PatchHostnameRequest { - hostname?: PatchAction - isDisabled?: PatchAction -} +import { PatchHostnameRequest } from './PatchHostnameRequest' export interface PatchAccountRequest { description?: PatchAction diff --git a/src/ClientApp/models/letsEncryptServer/account/requests/PatchContactsRequest.ts b/src/ClientApp/models/letsEncryptServer/account/requests/PatchContactsRequest.ts deleted file mode 100644 index 376f68a..0000000 --- a/src/ClientApp/models/letsEncryptServer/account/requests/PatchContactsRequest.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { PatchAction } from '@/models/PatchAction' - -export interface PatchContactsRequest { - contacts: PatchAction[] -} diff --git a/src/ClientApp/models/letsEncryptServer/account/requests/PatchHostnameRequest.ts b/src/ClientApp/models/letsEncryptServer/account/requests/PatchHostnameRequest.ts new file mode 100644 index 0000000..8096fb6 --- /dev/null +++ b/src/ClientApp/models/letsEncryptServer/account/requests/PatchHostnameRequest.ts @@ -0,0 +1,6 @@ +import { PatchAction } from '@/models/PatchAction' + +export interface PatchHostnameRequest { + hostname?: PatchAction + isDisabled?: PatchAction +} diff --git a/src/ClientApp/models/letsEncryptServer/certsFlow/PostAccountRequest.ts b/src/ClientApp/models/letsEncryptServer/account/requests/PostAccountRequest.ts similarity index 100% rename from src/ClientApp/models/letsEncryptServer/certsFlow/PostAccountRequest.ts rename to src/ClientApp/models/letsEncryptServer/account/requests/PostAccountRequest.ts diff --git a/src/ClientApp/models/letsEncryptServer/account/requests/PostContactsRequest.ts b/src/ClientApp/models/letsEncryptServer/account/requests/PostContactsRequest.ts deleted file mode 100644 index 2239abf..0000000 --- a/src/ClientApp/models/letsEncryptServer/account/requests/PostContactsRequest.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface PostContactsRequest { - contacts: string[] -} diff --git a/src/ClientApp/models/letsEncryptServer/account/requests/PutAccountRequest.ts b/src/ClientApp/models/letsEncryptServer/account/requests/PutAccountRequest.ts deleted file mode 100644 index f57164c..0000000 --- a/src/ClientApp/models/letsEncryptServer/account/requests/PutAccountRequest.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface PutAccountRequest { - description: string - contacts: string[] -} diff --git a/src/ClientApp/models/letsEncryptServer/account/requests/PutContactsRequest.ts b/src/ClientApp/models/letsEncryptServer/account/requests/PutContactsRequest.ts deleted file mode 100644 index 0ca5ecc..0000000 --- a/src/ClientApp/models/letsEncryptServer/account/requests/PutContactsRequest.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface PutContactsRequest { - contacts: string[] -} diff --git a/src/ClientApp/models/letsEncryptServer/account/responses/GetAccountResponse.ts b/src/ClientApp/models/letsEncryptServer/account/responses/GetAccountResponse.ts index 52f984d..78a8e1f 100644 --- a/src/ClientApp/models/letsEncryptServer/account/responses/GetAccountResponse.ts +++ b/src/ClientApp/models/letsEncryptServer/account/responses/GetAccountResponse.ts @@ -1,4 +1,5 @@ -import { HostnameResponse } from './HostnameResponse' +import { CacheAccount } from '@/entities/CacheAccount' +import { GetHostnameResponse } from './GetHostnameResponse' export interface GetAccountResponse { accountId: string @@ -6,6 +7,27 @@ export interface GetAccountResponse { description: string contacts: string[] challengeType?: string - hostnames?: HostnameResponse[] + hostnames?: GetHostnameResponse[] isStaging: boolean } + +const toCacheAccount = (account: GetAccountResponse): CacheAccount => { + return { + accountId: account.accountId, + isDisabled: account.isDisabled, + description: account.description, + contacts: account.contacts.map((contact) => contact), + challengeType: account.challengeType, + hostnames: + account.hostnames?.map((hostname) => ({ + hostname: hostname.hostname, + expires: new Date(hostname.expires), + isUpcomingExpire: hostname.isUpcomingExpire, + isDisabled: hostname.isDisabled + })) ?? [], + isStaging: account.isStaging, + isEditMode: false + } +} + +export { toCacheAccount } diff --git a/src/ClientApp/models/letsEncryptServer/account/responses/GetContactsResponse.ts b/src/ClientApp/models/letsEncryptServer/account/responses/GetContactsResponse.ts deleted file mode 100644 index 385289c..0000000 --- a/src/ClientApp/models/letsEncryptServer/account/responses/GetContactsResponse.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface GetContactsResponse { - contacts: string[] -} diff --git a/src/ClientApp/models/letsEncryptServer/account/responses/HostnameResponse.ts b/src/ClientApp/models/letsEncryptServer/account/responses/GetHostnameResponse.ts similarity index 69% rename from src/ClientApp/models/letsEncryptServer/account/responses/HostnameResponse.ts rename to src/ClientApp/models/letsEncryptServer/account/responses/GetHostnameResponse.ts index 2d077db..967295e 100644 --- a/src/ClientApp/models/letsEncryptServer/account/responses/HostnameResponse.ts +++ b/src/ClientApp/models/letsEncryptServer/account/responses/GetHostnameResponse.ts @@ -1,4 +1,4 @@ -export interface HostnameResponse { +export interface GetHostnameResponse { hostname: string expires: string isUpcomingExpire: boolean diff --git a/src/ClientApp/models/letsEncryptServer/account/responses/GetHostnamesResponse.ts b/src/ClientApp/models/letsEncryptServer/account/responses/GetHostnamesResponse.ts deleted file mode 100644 index 4d32edd..0000000 --- a/src/ClientApp/models/letsEncryptServer/account/responses/GetHostnamesResponse.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { HostnameResponse } from './HostnameResponse' - -export interface GetHostnamesResponse { - hostnames: HostnameResponse[] -} diff --git a/src/ClientApp/partials/accoutEdit.tsx b/src/ClientApp/partials/accoutEdit.tsx index abba49d..5e5ce4e 100644 --- a/src/ClientApp/partials/accoutEdit.tsx +++ b/src/ClientApp/partials/accoutEdit.tsx @@ -14,54 +14,40 @@ import { CustomInput, CustomRadioGroup } from '@/controls' -import { CacheAccount } from '@/entities/CacheAccount' +import { CacheAccount, toPatchAccountRequest } from '@/entities/CacheAccount' import { FaPlus, FaTrash } from 'react-icons/fa' import { ChallengeTypes } from '@/entities/ChallengeTypes' import { deepCopy } from '@/functions' import { ApiRoutes, GetApiRoute } from '@/ApiRoutes' -import { httpService } from '@/services/httpService' +import { httpService } from '@/services/HttpService' import { PatchAccountRequest } from '@/models/letsEncryptServer/account/requests/PatchAccountRequest' import { PatchOperation } from '@/models/PatchOperation' import { useAppDispatch } from '@/redux/store' import { showToast } from '@/redux/slices/toastSlice' +import { + GetAccountResponse, + toCacheAccount +} from '@/models/letsEncryptServer/account/responses/GetAccountResponse' interface AccountEditProps { account: CacheAccount - setAccount: Dispatch> onCancel?: () => void - onSubmit?: (account: CacheAccount) => void onDelete: (accountId: string) => void + onSubmit: (account: CacheAccount) => void } -const AccountEdit: React.FC = ({ - account, - setAccount, - onCancel, - onSubmit, - onDelete -}) => { +const AccountEdit: React.FC = (props) => { + const { account, onCancel, onDelete, onSubmit } = props + const dispatch = useAppDispatch() - const [newAccount, setNewAccount] = useState({ - description: { op: PatchOperation.None, value: account.description }, - isDisabled: { op: PatchOperation.None, value: account.isDisabled }, - contacts: account.contacts.map((contact) => ({ - op: PatchOperation.None, - value: contact - })), - hostnames: account.hostnames?.map((hostname) => ({ - hostname: { op: PatchOperation.None, value: hostname.hostname }, - isDisabled: { op: PatchOperation.None, value: hostname.isDisabled } - })) - }) + const [newAccount, setNewAccount] = useState( + toPatchAccountRequest(account) + ) const [newContact, setNewContact] = useState('') const [newHostname, setNewHostname] = useState('') - useEffect(() => { - console.log(newAccount) - }, [newAccount]) - const { value: description, error: descriptionError, @@ -163,6 +149,9 @@ const AccountEdit: React.FC = ({ return c }) .filter((c) => !(c.value === contact && c.op === PatchOperation.Add)) + + console.log(newAccount.contacts) + return newAccount }) } @@ -246,10 +235,23 @@ const AccountEdit: React.FC = ({ const handleSubmit = async (e: FormEvent) => { e.preventDefault() - httpService.patch( - GetApiRoute(ApiRoutes.ACCOUNT_ID, account.accountId), - newAccount - ) + if (!newAccount) return + + httpService + .patch< + PatchAccountRequest, + GetAccountResponse + >(GetApiRoute(ApiRoutes.ACCOUNT_ID, account.accountId), newAccount) + .then((response) => { + if (response.isSuccess && response.data) { + onSubmit?.(toCacheAccount(response.data)) + } else { + // Optionally, handle the error case, e.g., show an error message + dispatch( + showToast({ message: 'Failed to update account.', type: 'error' }) + ) + } + }) } const handleDelete = (accountId: string) => { @@ -268,7 +270,7 @@ const AccountEdit: React.FC = ({ title="Description" inputClassName="border p-2 rounded w-full" errorClassName="text-red-500 text-sm mt-1" - className="mr-2 flex-grow" + className="mr-2 w-full" />
@@ -277,27 +279,29 @@ const AccountEdit: React.FC = ({ checked={newAccount.isDisabled?.value ?? false} label="Disabled" onChange={handleIsDisabledChange} - className="mr-2 flex-grow" + className="mr-2" />

Contacts:

    - {newAccount.contacts?.map((contact) => ( -
  • -
    - {contact.value} - handleDeleteContact(contact.value ?? '')} - className="bg-red-500 text-white p-2 rounded ml-2" - > - - -
    -
  • - ))} + {newAccount.contacts + ?.filter((contact) => contact.op !== PatchOperation.Remove) + .map((contact) => ( +
  • +
    + {contact.value} + handleDeleteContact(contact.value ?? '')} + className="bg-red-500 text-white p-2 rounded ml-2" + > + + +
    +
  • + ))}
= ({ title="New Contact" inputClassName="border p-2 rounded w-full" errorClassName="text-red-500 text-sm mt-1" - className="mr-2 flex-grow" + className="mr-2 w-full" /> = ({ title="Challenge Type" enumType={ChallengeTypes} selectedValue={account.challengeType} - className="mr-2 flex-grow" + className="mr-2 w-full" disabled={true} />
@@ -334,34 +338,38 @@ const AccountEdit: React.FC = ({

Hostnames:

    - {newAccount.hostnames?.map((hostname) => ( -
  • -
    - {hostname.hostname?.value} -{' '} - - handleHostnameDisabledChange( - hostname.hostname?.value ?? '', - value - ) - } - /> -
    + {newAccount.hostnames + ?.filter( + (hostname) => hostname.hostname?.op !== PatchOperation.Remove + ) + .map((hostname) => ( +
  • +
    + {hostname.hostname?.value} -{' '} + + handleHostnameDisabledChange( + hostname.hostname?.value ?? '', + value + ) + } + /> +
    - - handleDeleteHostname(hostname.hostname?.value ?? '') - } - className="bg-red-500 text-white p-2 rounded ml-2" - > - - -
  • - ))} + + handleDeleteHostname(hostname.hostname?.value ?? '') + } + className="bg-red-500 text-white p-2 rounded ml-2" + > + + + + ))}
= ({ title="New Hostname" inputClassName="border p-2 rounded w-full" errorClassName="text-red-500 text-sm mt-1" - className="mr-2 flex-grow" + className="mr-2 w-full" /> = ({ ]} initialValue={account.isStaging ? 'staging' : 'production'} title="LetsEncrypt Environment" - className="mr-2 flex-grow" + className="mr-2 w-full" radioClassName="" errorClassName="text-red-500 text-sm mt-1" disabled={true} @@ -402,20 +410,20 @@ const AccountEdit: React.FC = ({ handleDelete(account.accountId)} - className="bg-red-500 text-white p-2 rounded ml-2" + className="bg-red-500 text-white p-2 rounded" > Cancel Save diff --git a/src/ClientApp/services/HttpService.tsx b/src/ClientApp/services/HttpService.tsx index e7b6223..9650222 100644 --- a/src/ClientApp/services/HttpService.tsx +++ b/src/ClientApp/services/HttpService.tsx @@ -73,6 +73,29 @@ class HttpService { }) } + private cleanObject = (obj: any): any => { + if (Array.isArray(obj)) { + const cleanedArray = obj + .map(this.cleanObject) + .filter((item) => item !== null && item !== undefined) + return cleanedArray.length > 0 ? cleanedArray : null + } else if (typeof obj === 'object' && obj !== null) { + if (obj.op !== undefined && obj.op === PatchOperation.None) { + return null + } + + const cleanedObject: any = {} + Object.keys(obj).forEach((key) => { + const cleanedValue = this.cleanObject(obj[key]) + if (cleanedValue !== null) { + cleanedObject[key] = cleanedValue + } + }) + return Object.keys(cleanedObject).length > 0 ? cleanedObject : null + } + return obj + } + private handleRequestInterceptors(xhr: XMLHttpRequest): void { this.requestInterceptors.forEach((interceptor) => { try { @@ -223,34 +246,12 @@ class HttpService { return await this.request('PUT', url, data) } - private cleanPatchRequest(obj: any): any { - if (Array.isArray(obj)) { - const cleanedArray = obj - .map(this.cleanPatchRequest) - .filter((item) => item !== null && item !== undefined) - return cleanedArray.length > 0 ? cleanedArray : null - } else if (typeof obj === 'object' && obj !== null) { - if (obj.op !== undefined && obj.op === PatchOperation.None) { - return null - } - - const cleanedObject: any = {} - Object.keys(obj).forEach((key) => { - const cleanedValue = this.cleanPatchRequest(obj[key]) - if (cleanedValue !== null) { - cleanedObject[key] = cleanedValue - } - }) - return Object.keys(cleanedObject).length > 0 ? cleanedObject : null - } - return obj - } - public async patch( url: string, data: TRequest ): Promise> { - const cleanedData = this.cleanPatchRequest(data) + // Clean the data before sending the patch request + const cleanedData = this.cleanObject(data) return await this.request('PATCH', url, cleanedData) } diff --git a/src/LetsEncrypt/Entities/LetsEncrypt/RegistrationCache.cs b/src/LetsEncrypt/Entities/LetsEncrypt/RegistrationCache.cs index bfe19d6..fbd6483 100644 --- a/src/LetsEncrypt/Entities/LetsEncrypt/RegistrationCache.cs +++ b/src/LetsEncrypt/Entities/LetsEncrypt/RegistrationCache.cs @@ -15,11 +15,10 @@ public class RegistrationCache { /// public required Guid AccountId { get; set; } public bool IsDisabled { get; set; } - public string? Description { get; set; } + public required string Description { get; set; } public required string[] Contacts { get; set; } - public string? ChallengeType { get; set; } - public required bool IsStaging { get; set; } + public string? ChallengeType { get; set; } #endregion diff --git a/src/LetsEncryptServer/Controllers/AccountController.cs b/src/LetsEncryptServer/Controllers/AccountController.cs index 890789d..c90c981 100644 --- a/src/LetsEncryptServer/Controllers/AccountController.cs +++ b/src/LetsEncryptServer/Controllers/AccountController.cs @@ -36,12 +36,6 @@ public class AccountController : ControllerBase { return result.ToActionResult(); } - [HttpPut("account/{accountId:guid}")] - public async Task PutAccount(Guid accountId, [FromBody] PutAccountRequest requestData) { - var result = await _accountService.PutAccountAsync(accountId, requestData); - return result.ToActionResult(); - } - [HttpPatch("account/{accountId:guid}")] public async Task PatchAccount(Guid accountId, [FromBody] PatchAccountRequest requestData) { var result = await _accountService.PatchAccountAsync(accountId, requestData); @@ -55,82 +49,4 @@ public class AccountController : ControllerBase { } #endregion - - #region Account Contacts - - [HttpGet("account/{accountId:guid}/contacts")] - public async Task GetContacts(Guid accountId) { - var result = await _accountService.GetContactsAsync(accountId); - return result.ToActionResult(); - } - - [HttpPost("account/{accountId:guid}/contacts")] - public async Task PostContacts(Guid accountId, [FromBody] PostContactsRequest requestData) { - //var result = await _accountService.PostContactsAsync(accountId, requestData); - //return result.ToActionResult(); - - return BadRequest("Not implemented"); - } - - [HttpPut("account/{accountId:guid}/contacts")] - public async Task PutContacts(Guid accountId, [FromBody] PutContactsRequest requestData) { - var result = await _accountService.PutContactsAsync(accountId, requestData); - return result.ToActionResult(); - } - - [HttpPatch("account/{accountId:guid}/contacts")] - public async Task PatchContacts(Guid accountId, [FromBody] PatchContactsRequest requestData) { - var result = await _accountService.PatchContactsAsync(accountId, requestData); - return result.ToActionResult(); - } - - [HttpDelete("account/{accountId:guid}/contact/{index:int}")] - public async Task DeleteContact(Guid accountId, int index) { - var result = await _accountService.DeleteContactAsync(accountId, index); - return result.ToActionResult(); - } - #endregion - - #region Account Hostnames - - [HttpGet("{accountId:guid}/hostnames")] - public async Task GetHostnames(Guid accountId) { - var result = await _accountService.GetHostnames(accountId); - return result.ToActionResult(); - } - - [HttpPost("account/{accountId:guid}/hostnames")] - public async Task PostHostname(Guid accountId, [FromBody] PostHostnamesRequest requestData) { - //var result = await _cacheService.PostHostnameAsync(accountId, requestData); - //return result.ToActionResult(); - - return BadRequest("Not implemented"); - } - - [HttpPut("account/{accountId:guid}/hostnames")] - public async Task PutHostname(Guid accountId, [FromBody] PutHostnamesRequest requestData) { - //var result = await _cacheService.PutHostnameAsync(accountId, requestData); - //return result.ToActionResult(); - - return BadRequest("Not implemented"); - } - - [HttpPatch("account/{accountId:guid}/hostnames")] - public async Task PatchHostname(Guid accountId, [FromBody] PatchHostnamesRequest requestData) { - //var result = await _cacheService.PatchHostnameAsync(accountId, requestData); - //return result.ToActionResult(); - - return BadRequest("Not implemented"); - } - - - [HttpDelete("account/{accountId:guid}/hostname/{index:int}")] - public async Task DeleteHostname(Guid accountId, int index) { - //var result = await _cacheService.DeleteHostnameAsync(accountId, index); - //return result.ToActionResult(); - - return BadRequest("Not implemented"); - } - - #endregion } diff --git a/src/LetsEncryptServer/Services/AccoutService.cs b/src/LetsEncryptServer/Services/AccoutService.cs index 66d40ad..79a64d7 100644 --- a/src/LetsEncryptServer/Services/AccoutService.cs +++ b/src/LetsEncryptServer/Services/AccoutService.cs @@ -17,15 +17,8 @@ public interface IAccountRestService { Task<(GetAccountResponse[]?, IDomainResult)> GetAccountsAsync(); Task<(GetAccountResponse?, IDomainResult)> GetAccountAsync(Guid accountId); Task<(GetAccountResponse?, IDomainResult)> PostAccountAsync(PostAccountRequest requestData); - Task<(GetAccountResponse?, IDomainResult)> PutAccountAsync(Guid accountId, PutAccountRequest requestData); Task<(GetAccountResponse?, IDomainResult)> PatchAccountAsync(Guid accountId, PatchAccountRequest requestData); - Task DeleteAccountAsync(Guid accountId); - Task<(GetContactsResponse?, IDomainResult)> GetContactsAsync(Guid accountId); - Task<(GetContactsResponse?, IDomainResult)> PostContactsAsync(Guid accountId, PostContactsRequest requestData); - Task<(GetAccountResponse?, IDomainResult)> PutContactsAsync(Guid accountId, PutContactsRequest requestData); - Task<(GetAccountResponse?, IDomainResult)> PatchContactsAsync(Guid accountId, PatchContactsRequest requestData); - Task DeleteContactAsync(Guid accountId, int index); - Task<(GetHostnamesResponse?, IDomainResult)> GetHostnames(Guid accountId); + Task DeleteAccountAsync(Guid accountId); } public interface IAccountService : IAccountInternalService, IAccountRestService { } @@ -75,67 +68,26 @@ public class AccountService : IAccountService { // TODO: check for overlapping hostnames in already existing accounts - var (sessionId, configureClientResult) = await _certsFlowService.ConfigureClientAsync(requestData.IsStaging); - if (!configureClientResult.IsSuccess || sessionId == null) { - //LogErrors(configureClientResult.Errors); - return (null, configureClientResult); - } - var sessionIdValue = sessionId.Value; + var (accountId, newCertsResult) = await _certsFlowService.FullFlow( + requestData.IsStaging, + null, + requestData.Description, + requestData.Contacts, + requestData.ChallengeType, + requestData.Hostnames + ); - var (_, initResult) = await _certsFlowService.InitAsync(sessionIdValue, null, requestData.Description, requestData.Contacts); - if (!initResult.IsSuccess) { - //LogErrors(initResult.Errors); - return (null, initResult); - } + if (!newCertsResult.IsSuccess || accountId == null) + return (null, newCertsResult); - var (_, newOrderResult) = await _certsFlowService.NewOrderAsync(sessionIdValue, requestData.Hostnames, requestData.ChallengeType); - if (!newOrderResult.IsSuccess) { - //LogErrors(newOrderResult.Errors); - return (null, newOrderResult); - } - var challengeResult = await _certsFlowService.CompleteChallengesAsync(sessionIdValue); - if (!challengeResult.IsSuccess) { - //LogErrors(challengeResult.Errors); - return (null, challengeResult); - } - var getOrderResult = await _certsFlowService.GetOrderAsync(sessionIdValue, requestData.Hostnames); - if (!getOrderResult.IsSuccess) { - //LogErrors(getOrderResult.Errors); - return (null, getOrderResult); - } - - var certs = await _certsFlowService.GetCertificatesAsync(sessionIdValue, requestData.Hostnames); - if (!certs.IsSuccess) { - //LogErrors(certs.Errors); - return (null, certs); - } - - var (_, applyCertsResult) = await _certsFlowService.ApplyCertificatesAsync(sessionIdValue, requestData.Hostnames); - if (!applyCertsResult.IsSuccess) { - //LogErrors(applyCertsResult.Errors); - return (null, applyCertsResult); - } - - return IDomainResult.Success(null); - } - - public async Task<(GetAccountResponse?, IDomainResult)> PutAccountAsync(Guid accountId, PutAccountRequest requestData) { - var (cache, loadResult) = await _cacheService.LoadAccountFromCacheAsync(accountId); + var (cache, loadResult) = await _cacheService.LoadAccountFromCacheAsync(accountId.Value); if (!loadResult.IsSuccess || cache == null) { return (null, loadResult); } - cache.Description = requestData.Description; - cache.Contacts = requestData.Contacts; - - var saveResult = await _cacheService.SaveToCacheAsync(accountId, cache); - if (!saveResult.IsSuccess) { - return (null, saveResult); - } - - return IDomainResult.Success(CreateGetAccountResponse(accountId, cache)); + return IDomainResult.Success(CreateGetAccountResponse(accountId.Value, cache)); } public async Task<(GetAccountResponse?, IDomainResult)> PatchAccountAsync(Guid accountId, PatchAccountRequest requestData) { @@ -152,7 +104,15 @@ public class AccountService : IAccountService { } } - if (requestData.Contacts != null && requestData.Contacts.Any()) { + if (requestData.IsDisabled != null) { + switch (requestData.IsDisabled.Op) { + case PatchOperation.Replace: + cache.IsDisabled = requestData.IsDisabled.Value; + break; + } + } + + if (requestData.Contacts?.Any() == true) { var contacts = cache.Contacts?.ToList() ?? new List(); foreach (var action in requestData.Contacts) { switch (action.Op) @@ -173,11 +133,81 @@ public class AccountService : IAccountService { cache.Contacts = contacts.ToArray(); } + + + + + var hostnamesToAdd = new List(); + var hostnamesToRemove = new List(); + + if (requestData.Hostnames?.Any() == true) { + var hostnames = cache.GetHosts().ToList(); + foreach (var action in requestData.Hostnames) { + + if (action.Hostname != null) { + switch (action.Hostname.Op) { + case PatchOperation.Add: + hostnamesToAdd.Add(action.Hostname.Value); + + break; + + case PatchOperation.Replace: + if (action.Hostname.Index != null && action.Hostname.Index >= 0 && action.Hostname.Index < hostnames.Count) + hostnames[action.Hostname.Index.Value].Hostname = action.Hostname.Value; + break; + + case PatchOperation.Remove: + hostnamesToRemove.Add(action.Hostname.Value); + + + break; + } + } + + if (action.IsDisabled != null) { + switch (action.IsDisabled.Op) { + case PatchOperation.Replace: + + break; + } + } + } + } + + var saveResult = await _cacheService.SaveToCacheAsync(accountId, cache); if (!saveResult.IsSuccess) { return (null, saveResult); } + + if (hostnamesToAdd.Count > 0) { + var (_, newCertsResult) = await _certsFlowService.FullFlow( + cache.IsStaging, + cache.AccountId, + cache.Description, + cache.Contacts, + cache.ChallengeType, + hostnamesToAdd.ToArray() + ); + + if (!newCertsResult.IsSuccess) + return (null, newCertsResult); + } + + + if (hostnamesToRemove.Count > 0) { + hostnamesToRemove.ForEach(hostname => { + cache.CachedCerts?.Remove(hostname); + }); + } + + + (cache, loadResult) = await _cacheService.LoadAccountFromCacheAsync(accountId); + if (!loadResult.IsSuccess || cache == null) { + return (null, loadResult); + } + return IDomainResult.Success(CreateGetAccountResponse(accountId, cache)); } @@ -189,117 +219,10 @@ public class AccountService : IAccountService { } #endregion - #region Contacts Operations + #region Helper Methods - public async Task<(GetContactsResponse?, IDomainResult)> GetContactsAsync(Guid accountId) { - var (cache, loadResult) = await _cacheService.LoadAccountFromCacheAsync(accountId); - if (!loadResult.IsSuccess || cache == null) { - return (null, loadResult); - } - - return IDomainResult.Success(new GetContactsResponse { - Contacts = cache.Contacts ?? Array.Empty() - }); - } - - public async Task<(GetContactsResponse?, IDomainResult)> PostContactsAsync(Guid accountId, PostContactsRequest requestData) { - return IDomainResult.Failed("Not implemented"); - } - - public async Task<(GetAccountResponse?, IDomainResult)> PutContactsAsync(Guid accountId, PutContactsRequest requestData) { - var (cache, loadResult) = await _cacheService.LoadAccountFromCacheAsync(accountId); - if (!loadResult.IsSuccess || cache == null) { - return (null, loadResult); - } - - cache.Contacts = requestData.Contacts; - var saveResult = await _cacheService.SaveToCacheAsync(accountId, cache); - if (!saveResult.IsSuccess) { - return (null, saveResult); - } - - return IDomainResult.Success(CreateGetAccountResponse(accountId, cache)); - } - - public async Task<(GetAccountResponse?, IDomainResult)> PatchContactsAsync(Guid accountId, PatchContactsRequest requestData) { - var (cache, loadResult) = await _cacheService.LoadAccountFromCacheAsync(accountId); - if (!loadResult.IsSuccess || cache == null) { - return (null, loadResult); - } - - var contacts = cache.Contacts?.ToList() ?? new List(); - - foreach (var contact in requestData.Contacts) { - switch (contact.Op) { - case PatchOperation.Add: - if (contact.Value != null) { - contacts.Add(contact.Value); - } - break; - case PatchOperation.Replace: - if (contact.Index.HasValue && contact.Index.Value >= 0 && contact.Index.Value < contacts.Count && contact.Value != null) { - contacts[contact.Index.Value] = contact.Value; - } - break; - case PatchOperation.Remove: - if (contact.Index.HasValue && contact.Index.Value >= 0 && contact.Index.Value < contacts.Count) { - contacts.RemoveAt(contact.Index.Value); - } - break; - default: - return (null, IDomainResult.Failed("Invalid patch operation.")); - } - } - - cache.Contacts = contacts.ToArray(); - var saveResult = await _cacheService.SaveToCacheAsync(accountId, cache); - if (!saveResult.IsSuccess) { - return (null, saveResult); - } - - return IDomainResult.Success(CreateGetAccountResponse(accountId, cache)); - } - - public async Task DeleteContactAsync(Guid accountId, int index) { - var (cache, loadResult) = await _cacheService.LoadAccountFromCacheAsync(accountId); - if (!loadResult.IsSuccess || cache == null) { - return loadResult; - } - - var contacts = cache.Contacts?.ToList() ?? new List(); - - if (index >= 0 && index < contacts.Count) { - contacts.RemoveAt(index); - } - - cache.Contacts = contacts.ToArray(); - var saveResult = await _cacheService.SaveToCacheAsync(accountId, cache); - if (!saveResult.IsSuccess) { - return saveResult; - } - - return IDomainResult.Success(); - } - - #endregion - - #region Hostnames Operations - - public async Task<(GetHostnamesResponse?, IDomainResult)> GetHostnames(Guid accountId) { - var (cache, loadResult) = await _cacheService.LoadAccountFromCacheAsync(accountId); - if (!loadResult.IsSuccess || cache?.CachedCerts == null) { - return (null, loadResult); - } - - var hostnames = GetHostnamesFromCache(cache); - - return IDomainResult.Success(new GetHostnamesResponse { - Hostnames = hostnames - }); - } - - private List GetHostnamesFromCache(RegistrationCache cache) { - var hosts = cache.GetHosts().Select(x => new HostnameResponse { + private List GetHostnamesFromCache(RegistrationCache cache) { + var hosts = cache.GetHosts().Select(x => new GetHostnameResponse { Hostname = x.Hostname, Expires = x.Expires, IsUpcomingExpire = x.IsUpcomingExpire, @@ -309,10 +232,6 @@ public class AccountService : IAccountService { return hosts; } - #endregion - - #region Helper Methods - private GetAccountResponse CreateGetAccountResponse(Guid accountId, RegistrationCache cache) { var hostnames = GetHostnamesFromCache(cache) ?? []; diff --git a/src/LetsEncryptServer/Services/CertsFlowService.cs b/src/LetsEncryptServer/Services/CertsFlowService.cs index 5eebade..1ee5dbb 100644 --- a/src/LetsEncryptServer/Services/CertsFlowService.cs +++ b/src/LetsEncryptServer/Services/CertsFlowService.cs @@ -23,6 +23,7 @@ public interface ICertsInternalService : ICertsCommonService { Task GetOrderAsync(Guid sessionId, string[] hostnames); Task GetCertificatesAsync(Guid sessionId, string[] hostnames); Task<(Dictionary?, IDomainResult)> ApplyCertificatesAsync(Guid sessionId, string[] hostnames); + Task<(Guid?, IDomainResult)> FullFlow(bool isStaging, Guid? accountId, string description, string[] contacts, string challengeType, string[] hostnames); } public interface ICertsRestService : ICertsCommonService { @@ -188,6 +189,39 @@ public class CertsFlowService : ICertsFlowService { return IDomainResult.Success(results); } + public async Task<(Guid?, IDomainResult)> FullFlow(bool isStaging, Guid? accountId, string description, string[] contacts, string challengeType, string[]hostnames) { + var (sessionId, configureClientResult) = await ConfigureClientAsync(isStaging); + if (!configureClientResult.IsSuccess || sessionId == null) + return (null, configureClientResult); + + (accountId, var initResult) = await InitAsync(sessionId.Value, accountId, description, contacts); + if (!initResult.IsSuccess) + return (null, initResult); + + var (_, newOrderResult) = await NewOrderAsync(sessionId.Value, hostnames, challengeType); + if (!newOrderResult.IsSuccess) + return (null, newOrderResult); + + var challengeResult = await CompleteChallengesAsync(sessionId.Value); + if (!challengeResult.IsSuccess) + return (null, challengeResult); + + var getOrderResult = await GetOrderAsync(sessionId.Value, hostnames); + if (!getOrderResult.IsSuccess) + return (null, getOrderResult); + + var certs = await GetCertificatesAsync(sessionId.Value, hostnames); + if (!certs.IsSuccess) + return (null, certs); + + var (_, applyCertsResult) = await ApplyCertificatesAsync(sessionId.Value, hostnames); + if (!applyCertsResult.IsSuccess) + return (null, applyCertsResult); + + return IDomainResult.Success(accountId); + } + + #endregion #region REST methods diff --git a/src/Models/LetsEncryptServer/Account/Requests/PatchAccountRequest.cs b/src/Models/LetsEncryptServer/Account/Requests/PatchAccountRequest.cs index 1eaef45..4d675f0 100644 --- a/src/Models/LetsEncryptServer/Account/Requests/PatchAccountRequest.cs +++ b/src/Models/LetsEncryptServer/Account/Requests/PatchAccountRequest.cs @@ -1,14 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; + -namespace MaksIT.Models.LetsEncryptServer.Account.Requests { - public class PatchAccountRequest { +namespace MaksIT.Models.LetsEncryptServer.Account.Requests; - public PatchAction? Description { get; set; } +public class PatchAccountRequest { - public List>? Contacts { get; set; } - } + public PatchAction? Description { get; set; } + + public PatchAction? IsDisabled { get; set; } + + public List>? Contacts { get; set; } + + public List? Hostnames { get; set; } } diff --git a/src/Models/LetsEncryptServer/Account/Requests/PatchContactsRequest - Copy.cs b/src/Models/LetsEncryptServer/Account/Requests/PatchContactsRequest - Copy.cs deleted file mode 100644 index eb76f4e..0000000 --- a/src/Models/LetsEncryptServer/Account/Requests/PatchContactsRequest - Copy.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MaksIT.Models.LetsEncryptServer.Account.Requests { - - public class PatchContactsRequest { - public List> Contacts { get; set; } - } -} diff --git a/src/Models/LetsEncryptServer/Account/Requests/PatchHostnameRequest.cs b/src/Models/LetsEncryptServer/Account/Requests/PatchHostnameRequest.cs new file mode 100644 index 0000000..a9d36e3 --- /dev/null +++ b/src/Models/LetsEncryptServer/Account/Requests/PatchHostnameRequest.cs @@ -0,0 +1,9 @@ + + +namespace MaksIT.Models.LetsEncryptServer.Account.Requests; +public class PatchHostnameRequest { + public PatchAction Hostname { get; set; } + + public PatchAction IsDisabled { get; set; } +} + diff --git a/src/Models/LetsEncryptServer/Account/Requests/PatchHostnamesRequest.cs b/src/Models/LetsEncryptServer/Account/Requests/PatchHostnamesRequest.cs deleted file mode 100644 index 03a350d..0000000 --- a/src/Models/LetsEncryptServer/Account/Requests/PatchHostnamesRequest.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MaksIT.Models.LetsEncryptServer.Account.Requests { - - public class PatchHostnamesRequest { - public List> Hostnames { get; set; } - } -} diff --git a/src/Models/LetsEncryptServer/Account/Requests/PostAccountRequest.cs b/src/Models/LetsEncryptServer/Account/Requests/PostAccountRequest.cs index 2bdd365..e373c7f 100644 --- a/src/Models/LetsEncryptServer/Account/Requests/PostAccountRequest.cs +++ b/src/Models/LetsEncryptServer/Account/Requests/PostAccountRequest.cs @@ -1,25 +1,24 @@ using System.ComponentModel.DataAnnotations; -namespace MaksIT.Models.LetsEncryptServer.Account.Requests { - public class PostAccountRequest : IValidatableObject { - public required string Description { get; set; } - public required string[] Contacts { get; set; } - public required string ChallengeType { get; set; } - public required string[] Hostnames { get; set; } - public required bool IsStaging { get; set; } +namespace MaksIT.Models.LetsEncryptServer.Account.Requests; +public class PostAccountRequest : IValidatableObject { + public required string Description { get; set; } + public required string[] Contacts { get; set; } + public required string ChallengeType { get; set; } + public required string[] Hostnames { get; set; } + public required bool IsStaging { get; set; } - public IEnumerable Validate(ValidationContext validationContext) { - if (string.IsNullOrWhiteSpace(Description)) - yield return new ValidationResult("Description is required", new[] { nameof(Description) }); + public IEnumerable Validate(ValidationContext validationContext) { + if (string.IsNullOrWhiteSpace(Description)) + yield return new ValidationResult("Description is required", new[] { nameof(Description) }); - if (Contacts == null || Contacts.Length == 0) - yield return new ValidationResult("Contacts is required", new[] { nameof(Contacts) }); + if (Contacts == null || Contacts.Length == 0) + yield return new ValidationResult("Contacts is required", new[] { nameof(Contacts) }); - if (Hostnames == null || Hostnames.Length == 0) - yield return new ValidationResult("Hostnames is required", new[] { nameof(Hostnames) }); + if (Hostnames == null || Hostnames.Length == 0) + yield return new ValidationResult("Hostnames is required", new[] { nameof(Hostnames) }); - if (string.IsNullOrWhiteSpace(ChallengeType) && ChallengeType != "http-01") - yield return new ValidationResult("ChallengeType is required", new[] { nameof(ChallengeType) }); - } + if (string.IsNullOrWhiteSpace(ChallengeType) && ChallengeType != "http-01") + yield return new ValidationResult("ChallengeType is required", new[] { nameof(ChallengeType) }); } } diff --git a/src/Models/LetsEncryptServer/Account/Requests/PostContactsRequest.cs b/src/Models/LetsEncryptServer/Account/Requests/PostContactsRequest.cs deleted file mode 100644 index 837cece..0000000 --- a/src/Models/LetsEncryptServer/Account/Requests/PostContactsRequest.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MaksIT.Models.LetsEncryptServer.Account.Requests { - public class PostContactsRequest : IValidatableObject { - - public required string[] Contacts { get; set; } - - public IEnumerable Validate(ValidationContext validationContext) { - - if (Contacts == null || Contacts.Length == 0) - yield return new ValidationResult("Contacts is required", new[] { nameof(Contacts) }); - } - } - } \ No newline at end of file diff --git a/src/Models/LetsEncryptServer/Account/Requests/PostHostnamesRequest.cs b/src/Models/LetsEncryptServer/Account/Requests/PostHostnamesRequest.cs deleted file mode 100644 index 0bfdcdc..0000000 --- a/src/Models/LetsEncryptServer/Account/Requests/PostHostnamesRequest.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MaksIT.Models.LetsEncryptServer.Account.Requests { - public class PostHostnamesRequest : IValidatableObject { - public required string[] Hostnames { get; set; } - - public IEnumerable Validate(ValidationContext validationContext) { - if (Hostnames == null || Hostnames.Length == 0) - yield return new ValidationResult("Hostnames is required", new[] { nameof(Hostnames) }); - } - } -} diff --git a/src/Models/LetsEncryptServer/Account/Requests/PutAccountRequest.cs b/src/Models/LetsEncryptServer/Account/Requests/PutAccountRequest.cs deleted file mode 100644 index f86800e..0000000 --- a/src/Models/LetsEncryptServer/Account/Requests/PutAccountRequest.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MaksIT.Models.LetsEncryptServer.Account.Requests { - public class PutAccountRequest : IValidatableObject { - public required string Description { get; set; } - public required string[] Contacts { get; set; } - - public IEnumerable Validate(ValidationContext validationContext) { - if (string.IsNullOrWhiteSpace(Description)) - yield return new ValidationResult("Description is required", new[] { nameof(Description) }); - - if (Contacts == null || Contacts.Length == 0) - yield return new ValidationResult("Contacts is required", new[] { nameof(Contacts) }); - } - } -} diff --git a/src/Models/LetsEncryptServer/Account/Requests/PutContactsRequest.cs b/src/Models/LetsEncryptServer/Account/Requests/PutContactsRequest.cs deleted file mode 100644 index 055d240..0000000 --- a/src/Models/LetsEncryptServer/Account/Requests/PutContactsRequest.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.ComponentModel.DataAnnotations; - - -namespace MaksIT.Models.LetsEncryptServer.Account.Requests { - public class PutContactsRequest : IValidatableObject { - - public required string[] Contacts { get; set; } - - public IEnumerable Validate(ValidationContext validationContext) { - - if (Contacts == null || Contacts.Length == 0) - yield return new ValidationResult("Contacts is required", new[] { nameof(Contacts) }); - } - } -} diff --git a/src/Models/LetsEncryptServer/Account/Requests/PutHostnamesRequest.cs b/src/Models/LetsEncryptServer/Account/Requests/PutHostnamesRequest.cs deleted file mode 100644 index 7eb7b58..0000000 --- a/src/Models/LetsEncryptServer/Account/Requests/PutHostnamesRequest.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MaksIT.Models.LetsEncryptServer.Account.Requests { - public class PutHostnamesRequest : IValidatableObject { - public string[] Hostnames { get; set; } - - public IEnumerable Validate(ValidationContext validationContext) { - if (Hostnames == null || Hostnames.Length == 0) - yield return new ValidationResult("Hostnames is required", new[] { nameof(Hostnames) }); - } - } -} diff --git a/src/Models/LetsEncryptServer/Account/Responses/GetAccountResponse.cs b/src/Models/LetsEncryptServer/Account/Responses/GetAccountResponse.cs index 73d7b81..24ee9ab 100644 --- a/src/Models/LetsEncryptServer/Account/Responses/GetAccountResponse.cs +++ b/src/Models/LetsEncryptServer/Account/Responses/GetAccountResponse.cs @@ -15,7 +15,7 @@ namespace MaksIT.Models.LetsEncryptServer.Account.Responses { public string? ChallengeType { get; set; } - public HostnameResponse[]? Hostnames { get; set; } + public GetHostnameResponse[]? Hostnames { get; set; } public required bool IsStaging { get; set; } } diff --git a/src/Models/LetsEncryptServer/Account/Responses/GetContactsResponse.cs b/src/Models/LetsEncryptServer/Account/Responses/GetContactsResponse.cs deleted file mode 100644 index ae55445..0000000 --- a/src/Models/LetsEncryptServer/Account/Responses/GetContactsResponse.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MaksIT.Models.LetsEncryptServer.Account.Responses { - public class GetContactsResponse { - public string[] Contacts { get; set; } - } -} diff --git a/src/Models/LetsEncryptServer/Account/Responses/HostnameResponse.cs b/src/Models/LetsEncryptServer/Account/Responses/GetHostnameResponse.cs similarity index 90% rename from src/Models/LetsEncryptServer/Account/Responses/HostnameResponse.cs rename to src/Models/LetsEncryptServer/Account/Responses/GetHostnameResponse.cs index 6a98912..de40757 100644 --- a/src/Models/LetsEncryptServer/Account/Responses/HostnameResponse.cs +++ b/src/Models/LetsEncryptServer/Account/Responses/GetHostnameResponse.cs @@ -5,7 +5,7 @@ using System.Text; using System.Threading.Tasks; namespace MaksIT.Models.LetsEncryptServer.Account.Responses { - public class HostnameResponse { + public class GetHostnameResponse { public required string Hostname { get; set; } public DateTime Expires { get; set; } public bool IsUpcomingExpire { get; set; } diff --git a/src/Models/LetsEncryptServer/Account/Responses/GetHostnamesResponse.cs b/src/Models/LetsEncryptServer/Account/Responses/GetHostnamesResponse.cs deleted file mode 100644 index f9758ba..0000000 --- a/src/Models/LetsEncryptServer/Account/Responses/GetHostnamesResponse.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MaksIT.Models.LetsEncryptServer.Account.Responses { - - public class GetHostnamesResponse { - public List Hostnames { get; set; } - } -}