mirror of
https://github.com/MAKS-IT-COM/maksit-certs-ui.git
synced 2025-12-31 04:00:03 +01:00
(feature): account patch operations init and webapi cleanup
This commit is contained in:
parent
3e0c25158e
commit
8aa535447e
@ -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}
|
||||
/>
|
||||
</div>
|
||||
@ -206,9 +190,12 @@ export default function Page() {
|
||||
{editingAccount && (
|
||||
<AccountEdit
|
||||
account={editingAccount}
|
||||
setAccount={setEditingAccount}
|
||||
onCancel={() => setEditingAccount(null)}
|
||||
onDelete={deleteAccount}
|
||||
onSubmit={(account) => {
|
||||
setEditingAccount(null)
|
||||
handleAccountUpdate(account)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</OffCanvas>
|
||||
|
||||
@ -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'
|
||||
|
||||
|
||||
@ -71,27 +71,41 @@ const CustomSelect: React.FC<CustomSelectProps> = ({
|
||||
|
||||
return (
|
||||
<div className={`flex flex-col ${className}`} ref={selectBoxRef}>
|
||||
{title && <label className="mb-1">{title}</label>}
|
||||
{title && <label className="mb-1 text-gray-700">{title}</label>}
|
||||
<div
|
||||
className={`relative w-64 ${disabled ? 'opacity-50 cursor-not-allowed' : ''}`}
|
||||
className={`relative w-64 ${disabled ? 'opacity-50 cursor-not-allowed' : readOnly ? 'cursor-not-allowed' : ''}`}
|
||||
>
|
||||
<div
|
||||
className={`p-2 border ${disabled ? 'border-gray-200' : 'border-gray-300'} rounded cursor-pointer flex justify-between items-center ${disabled ? 'cursor-not-allowed' : ''} ${selectBoxClassName}`}
|
||||
className={`p-2 border rounded flex justify-between items-center ${
|
||||
disabled
|
||||
? 'border-gray-200 bg-gray-100 text-gray-500'
|
||||
: readOnly
|
||||
? 'border-gray-300 bg-white cursor-not-allowed'
|
||||
: 'border-gray-300 bg-white cursor-pointer hover:border-gray-400'
|
||||
} ${selectBoxClassName}`}
|
||||
onClick={handleToggle}
|
||||
>
|
||||
{selectedOption ? selectedOption.label : 'Select an option'}
|
||||
<span className={`${disabled ? 'text-gray-500' : ''}`}>
|
||||
{selectedOption ? selectedOption.label : 'Select an option'}
|
||||
</span>
|
||||
|
||||
{isOpen ? (
|
||||
<FaChevronUp className="ml-2" />
|
||||
<FaChevronUp
|
||||
className={`ml-2 ${disabled ? 'text-gray-500' : ''}`}
|
||||
/>
|
||||
) : (
|
||||
<FaChevronDown className="ml-2" />
|
||||
<FaChevronDown
|
||||
className={`ml-2 ${disabled ? 'text-gray-500' : ''}`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{isOpen && (
|
||||
<ul className="absolute z-10 w-full mt-1 overflow-y-auto bg-white border border-gray-300 max-h-60">
|
||||
<ul className="absolute z-10 w-full mt-1 bg-white border border-gray-300 rounded shadow-lg max-h-60 overflow-y-auto">
|
||||
{options.map((option) => (
|
||||
<li
|
||||
key={option.value}
|
||||
className={`p-2 hover:bg-gray-200 ${readOnly || disabled ? 'cursor-not-allowed' : 'cursor-pointer'}`}
|
||||
className={'p-2'}
|
||||
onClick={() => handleOptionClick(option)}
|
||||
>
|
||||
{option.label}
|
||||
@ -100,6 +114,7 @@ const CustomSelect: React.FC<CustomSelectProps> = ({
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<p className={`text-red-500 mt-1 ${errorClassName}`}>{error}</p>
|
||||
)}
|
||||
|
||||
@ -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 }
|
||||
|
||||
@ -1,9 +1,5 @@
|
||||
import { PatchAction } from '@/models/PatchAction'
|
||||
|
||||
export interface PatchHostnameRequest {
|
||||
hostname?: PatchAction<string>
|
||||
isDisabled?: PatchAction<boolean>
|
||||
}
|
||||
import { PatchHostnameRequest } from './PatchHostnameRequest'
|
||||
|
||||
export interface PatchAccountRequest {
|
||||
description?: PatchAction<string>
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
import { PatchAction } from '@/models/PatchAction'
|
||||
|
||||
export interface PatchContactsRequest {
|
||||
contacts: PatchAction<string>[]
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
import { PatchAction } from '@/models/PatchAction'
|
||||
|
||||
export interface PatchHostnameRequest {
|
||||
hostname?: PatchAction<string>
|
||||
isDisabled?: PatchAction<boolean>
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
export interface PostContactsRequest {
|
||||
contacts: string[]
|
||||
}
|
||||
@ -1,4 +0,0 @@
|
||||
export interface PutAccountRequest {
|
||||
description: string
|
||||
contacts: string[]
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
export interface PutContactsRequest {
|
||||
contacts: string[]
|
||||
}
|
||||
@ -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 }
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
export interface GetContactsResponse {
|
||||
contacts: string[]
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
export interface HostnameResponse {
|
||||
export interface GetHostnameResponse {
|
||||
hostname: string
|
||||
expires: string
|
||||
isUpcomingExpire: boolean
|
||||
@ -1,5 +0,0 @@
|
||||
import { HostnameResponse } from './HostnameResponse'
|
||||
|
||||
export interface GetHostnamesResponse {
|
||||
hostnames: HostnameResponse[]
|
||||
}
|
||||
@ -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<SetStateAction<CacheAccount | null>>
|
||||
onCancel?: () => void
|
||||
onSubmit?: (account: CacheAccount) => void
|
||||
onDelete: (accountId: string) => void
|
||||
onSubmit: (account: CacheAccount) => void
|
||||
}
|
||||
|
||||
const AccountEdit: React.FC<AccountEditProps> = ({
|
||||
account,
|
||||
setAccount,
|
||||
onCancel,
|
||||
onSubmit,
|
||||
onDelete
|
||||
}) => {
|
||||
const AccountEdit: React.FC<AccountEditProps> = (props) => {
|
||||
const { account, onCancel, onDelete, onSubmit } = props
|
||||
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
const [newAccount, setNewAccount] = useState<PatchAccountRequest>({
|
||||
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<PatchAccountRequest>(
|
||||
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<AccountEditProps> = ({
|
||||
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<AccountEditProps> = ({
|
||||
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault()
|
||||
|
||||
httpService.patch<PatchAccountRequest, CacheAccount>(
|
||||
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<AccountEditProps> = ({
|
||||
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"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -277,27 +279,29 @@ const AccountEdit: React.FC<AccountEditProps> = ({
|
||||
checked={newAccount.isDisabled?.value ?? false}
|
||||
label="Disabled"
|
||||
onChange={handleIsDisabledChange}
|
||||
className="mr-2 flex-grow"
|
||||
className="mr-2"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-4">
|
||||
<h3 className="text-xl font-medium mb-2">Contacts:</h3>
|
||||
<ul className="list-disc list-inside pl-4 mb-2">
|
||||
{newAccount.contacts?.map((contact) => (
|
||||
<li key={contact.value} className="text-gray-700 mb-2">
|
||||
<div className="inline-flex">
|
||||
{contact.value}
|
||||
<CustomButton
|
||||
type="button"
|
||||
onClick={() => handleDeleteContact(contact.value ?? '')}
|
||||
className="bg-red-500 text-white p-2 rounded ml-2"
|
||||
>
|
||||
<FaTrash />
|
||||
</CustomButton>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
{newAccount.contacts
|
||||
?.filter((contact) => contact.op !== PatchOperation.Remove)
|
||||
.map((contact) => (
|
||||
<li key={contact.value} className="text-gray-700 mb-2">
|
||||
<div className="inline-flex">
|
||||
{contact.value}
|
||||
<CustomButton
|
||||
type="button"
|
||||
onClick={() => handleDeleteContact(contact.value ?? '')}
|
||||
className="bg-red-500 text-white p-2 rounded ml-2"
|
||||
>
|
||||
<FaTrash />
|
||||
</CustomButton>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className="flex items-center mb-4">
|
||||
<CustomInput
|
||||
@ -309,7 +313,7 @@ const AccountEdit: React.FC<AccountEditProps> = ({
|
||||
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"
|
||||
/>
|
||||
<CustomButton
|
||||
type="button"
|
||||
@ -326,7 +330,7 @@ const AccountEdit: React.FC<AccountEditProps> = ({
|
||||
title="Challenge Type"
|
||||
enumType={ChallengeTypes}
|
||||
selectedValue={account.challengeType}
|
||||
className="mr-2 flex-grow"
|
||||
className="mr-2 w-full"
|
||||
disabled={true}
|
||||
/>
|
||||
</div>
|
||||
@ -334,34 +338,38 @@ const AccountEdit: React.FC<AccountEditProps> = ({
|
||||
<div>
|
||||
<h3 className="text-xl font-medium mb-2">Hostnames:</h3>
|
||||
<ul className="list-disc list-inside pl-4 mb-2">
|
||||
{newAccount.hostnames?.map((hostname) => (
|
||||
<li key={hostname.hostname?.value} className="text-gray-700 mb-2">
|
||||
<div className="inline-flex">
|
||||
{hostname.hostname?.value} -{' '}
|
||||
<CustomCheckbox
|
||||
className="ml-2"
|
||||
checked={hostname.isDisabled?.value ?? false}
|
||||
label="Disabled"
|
||||
onChange={(value) =>
|
||||
handleHostnameDisabledChange(
|
||||
hostname.hostname?.value ?? '',
|
||||
value
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
{newAccount.hostnames
|
||||
?.filter(
|
||||
(hostname) => hostname.hostname?.op !== PatchOperation.Remove
|
||||
)
|
||||
.map((hostname) => (
|
||||
<li key={hostname.hostname?.value} className="text-gray-700 mb-2">
|
||||
<div className="inline-flex items-center">
|
||||
{hostname.hostname?.value} -{' '}
|
||||
<CustomCheckbox
|
||||
className="ml-2"
|
||||
checked={hostname.isDisabled?.value ?? false}
|
||||
label="Disabled"
|
||||
onChange={(value) =>
|
||||
handleHostnameDisabledChange(
|
||||
hostname.hostname?.value ?? '',
|
||||
value
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<CustomButton
|
||||
type="button"
|
||||
onClick={() =>
|
||||
handleDeleteHostname(hostname.hostname?.value ?? '')
|
||||
}
|
||||
className="bg-red-500 text-white p-2 rounded ml-2"
|
||||
>
|
||||
<FaTrash />
|
||||
</CustomButton>
|
||||
</li>
|
||||
))}
|
||||
<CustomButton
|
||||
type="button"
|
||||
onClick={() =>
|
||||
handleDeleteHostname(hostname.hostname?.value ?? '')
|
||||
}
|
||||
className="bg-red-500 text-white p-2 rounded ml-2"
|
||||
>
|
||||
<FaTrash />
|
||||
</CustomButton>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className="flex items-center">
|
||||
<CustomInput
|
||||
@ -373,7 +381,7 @@ const AccountEdit: React.FC<AccountEditProps> = ({
|
||||
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"
|
||||
/>
|
||||
<CustomButton
|
||||
type="button"
|
||||
@ -392,7 +400,7 @@ const AccountEdit: React.FC<AccountEditProps> = ({
|
||||
]}
|
||||
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<AccountEditProps> = ({
|
||||
<CustomButton
|
||||
type="button"
|
||||
onClick={() => handleDelete(account.accountId)}
|
||||
className="bg-red-500 text-white p-2 rounded ml-2"
|
||||
className="bg-red-500 text-white p-2 rounded"
|
||||
>
|
||||
<FaTrash />
|
||||
</CustomButton>
|
||||
<CustomButton
|
||||
type="button"
|
||||
onClick={handleCancel}
|
||||
className="bg-yellow-500 text-white p-2 rounded ml-2"
|
||||
className="bg-yellow-500 text-white p-2 rounded"
|
||||
>
|
||||
Cancel
|
||||
</CustomButton>
|
||||
<CustomButton
|
||||
type="submit"
|
||||
className="bg-green-500 text-white p-2 rounded ml-2"
|
||||
className="bg-green-500 text-white p-2 rounded"
|
||||
>
|
||||
Save
|
||||
</CustomButton>
|
||||
|
||||
@ -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<TResponse>('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<TRequest, TResponse>(
|
||||
url: string,
|
||||
data: TRequest
|
||||
): Promise<HttpResponse<TResponse>> {
|
||||
const cleanedData = this.cleanPatchRequest(data)
|
||||
// Clean the data before sending the patch request
|
||||
const cleanedData = this.cleanObject(data)
|
||||
return await this.request<TResponse>('PATCH', url, cleanedData)
|
||||
}
|
||||
|
||||
|
||||
@ -15,11 +15,10 @@ public class RegistrationCache {
|
||||
/// </summary>
|
||||
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
|
||||
|
||||
|
||||
|
||||
@ -36,12 +36,6 @@ public class AccountController : ControllerBase {
|
||||
return result.ToActionResult();
|
||||
}
|
||||
|
||||
[HttpPut("account/{accountId:guid}")]
|
||||
public async Task<IActionResult> PutAccount(Guid accountId, [FromBody] PutAccountRequest requestData) {
|
||||
var result = await _accountService.PutAccountAsync(accountId, requestData);
|
||||
return result.ToActionResult();
|
||||
}
|
||||
|
||||
[HttpPatch("account/{accountId:guid}")]
|
||||
public async Task<IActionResult> 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<IActionResult> GetContacts(Guid accountId) {
|
||||
var result = await _accountService.GetContactsAsync(accountId);
|
||||
return result.ToActionResult();
|
||||
}
|
||||
|
||||
[HttpPost("account/{accountId:guid}/contacts")]
|
||||
public async Task<IActionResult> 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<IActionResult> PutContacts(Guid accountId, [FromBody] PutContactsRequest requestData) {
|
||||
var result = await _accountService.PutContactsAsync(accountId, requestData);
|
||||
return result.ToActionResult();
|
||||
}
|
||||
|
||||
[HttpPatch("account/{accountId:guid}/contacts")]
|
||||
public async Task<IActionResult> 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<IActionResult> 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<IActionResult> GetHostnames(Guid accountId) {
|
||||
var result = await _accountService.GetHostnames(accountId);
|
||||
return result.ToActionResult();
|
||||
}
|
||||
|
||||
[HttpPost("account/{accountId:guid}/hostnames")]
|
||||
public async Task<IActionResult> 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<IActionResult> 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<IActionResult> 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<IActionResult> DeleteHostname(Guid accountId, int index) {
|
||||
//var result = await _cacheService.DeleteHostnameAsync(accountId, index);
|
||||
//return result.ToActionResult();
|
||||
|
||||
return BadRequest("Not implemented");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@ -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<IDomainResult> 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<IDomainResult> DeleteContactAsync(Guid accountId, int index);
|
||||
Task<(GetHostnamesResponse?, IDomainResult)> GetHostnames(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<GetAccountResponse?>(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<string>();
|
||||
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<string>();
|
||||
var hostnamesToRemove = new List<string>();
|
||||
|
||||
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<string>()
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<(GetContactsResponse?, IDomainResult)> PostContactsAsync(Guid accountId, PostContactsRequest requestData) {
|
||||
return IDomainResult.Failed<GetContactsResponse?>("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<string>();
|
||||
|
||||
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<IDomainResult> 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<string>();
|
||||
|
||||
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<HostnameResponse> GetHostnamesFromCache(RegistrationCache cache) {
|
||||
var hosts = cache.GetHosts().Select(x => new HostnameResponse {
|
||||
private List<GetHostnameResponse> 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) ?? [];
|
||||
|
||||
|
||||
@ -23,6 +23,7 @@ public interface ICertsInternalService : ICertsCommonService {
|
||||
Task<IDomainResult> GetOrderAsync(Guid sessionId, string[] hostnames);
|
||||
Task<IDomainResult> GetCertificatesAsync(Guid sessionId, string[] hostnames);
|
||||
Task<(Dictionary<string, string>?, 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
|
||||
|
||||
@ -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<string>? Description { get; set; }
|
||||
public class PatchAccountRequest {
|
||||
|
||||
public List<PatchAction<string>>? Contacts { get; set; }
|
||||
}
|
||||
public PatchAction<string>? Description { get; set; }
|
||||
|
||||
public PatchAction<bool>? IsDisabled { get; set; }
|
||||
|
||||
public List<PatchAction<string>>? Contacts { get; set; }
|
||||
|
||||
public List<PatchHostnameRequest>? Hostnames { get; set; }
|
||||
}
|
||||
|
||||
@ -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<PatchAction<string>> Contacts { get; set; }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
|
||||
|
||||
namespace MaksIT.Models.LetsEncryptServer.Account.Requests;
|
||||
public class PatchHostnameRequest {
|
||||
public PatchAction<string> Hostname { get; set; }
|
||||
|
||||
public PatchAction<bool> IsDisabled { get; set; }
|
||||
}
|
||||
|
||||
@ -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<PatchAction<string>> Hostnames { get; set; }
|
||||
}
|
||||
}
|
||||
@ -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<ValidationResult> Validate(ValidationContext validationContext) {
|
||||
if (string.IsNullOrWhiteSpace(Description))
|
||||
yield return new ValidationResult("Description is required", new[] { nameof(Description) });
|
||||
public IEnumerable<ValidationResult> 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) });
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<ValidationResult> Validate(ValidationContext validationContext) {
|
||||
|
||||
if (Contacts == null || Contacts.Length == 0)
|
||||
yield return new ValidationResult("Contacts is required", new[] { nameof(Contacts) });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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<ValidationResult> Validate(ValidationContext validationContext) {
|
||||
if (Hostnames == null || Hostnames.Length == 0)
|
||||
yield return new ValidationResult("Hostnames is required", new[] { nameof(Hostnames) });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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<ValidationResult> 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) });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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<ValidationResult> Validate(ValidationContext validationContext) {
|
||||
|
||||
if (Contacts == null || Contacts.Length == 0)
|
||||
yield return new ValidationResult("Contacts is required", new[] { nameof(Contacts) });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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<ValidationResult> Validate(ValidationContext validationContext) {
|
||||
if (Hostnames == null || Hostnames.Length == 0)
|
||||
yield return new ValidationResult("Hostnames is required", new[] { nameof(Hostnames) });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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; }
|
||||
}
|
||||
|
||||
@ -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; }
|
||||
}
|
||||
}
|
||||
@ -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; }
|
||||
@ -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<HostnameResponse> Hostnames { get; set; }
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user