-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e9c5bb0
commit e3e94c9
Showing
1 changed file
with
152 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
import { Flags } from "@oclif/core"; | ||
import { assertStatus } from "@mittwald/api-client-commons"; | ||
import { projectFlags } from "../../../lib/resources/project/flags.js"; | ||
import { ExecRenderBaseCommand } from "../../../lib/basecommands/ExecRenderBaseCommand.js"; | ||
import { | ||
makeProcessRenderer, | ||
processFlags, | ||
} from "../../../rendering/process/process_flags.js"; | ||
import { Text } from "ink"; | ||
import { Success } from "../../../rendering/react/components/Success.js"; | ||
import { ReactNode } from "react"; | ||
import { ProcessRenderer } from "../../../rendering/process/process.js"; | ||
import { FlagInput, OutputFlags } from "@oclif/core/lib/interfaces/parser.js"; | ||
import crypto from "crypto"; | ||
import { Value } from "../../../rendering/react/components/Value.js"; | ||
|
||
type CreateResult = { | ||
addressId: string; | ||
generatedPassword: string | null; | ||
}; | ||
|
||
export default class Create extends ExecRenderBaseCommand< | ||
typeof Create, | ||
CreateResult | ||
> { | ||
static summary = "Create a new mail deliverybox"; | ||
static description = `\ | ||
This command can be used to create a new mail deliverybox in a project. | ||
A mail address is either associated with a mailbox, or forwards to another address. // TODO: keine Ahnung | ||
When running this command with the --quiet flag, the output will contain the ID of the newly created deliverybox. | ||
In addition, when run with --generated-password the output will be the ID of the newly created deliverybox, followed by a tab character and the generated password.`; | ||
static flags = { | ||
...projectFlags, | ||
...processFlags, | ||
description: Flags.string({ | ||
char: "d", | ||
summary: "mail devliverybox description", | ||
required: true, | ||
}), | ||
password: Flags.string({ | ||
summary: "deliverybox password", | ||
description: | ||
"This is the password that should be used for the deliverybox; if omitted, the command will prompt interactively for a password.\n\nCAUTION: providing this flag may log your password in your shell history!", | ||
}), | ||
"random-password": Flags.boolean({ | ||
summary: "generate a random password", | ||
description: | ||
"This flag will cause the command to generate a random 32-character password for the deliverybox; when running with --quiet, the devliverybox ID and the password will be printed to stdout, separated by a tab character.", | ||
}), | ||
}; | ||
|
||
static examples = [ | ||
{ | ||
description: "Create non-interactively with password", | ||
command: | ||
"$ read -s PASSWORD &&\n <%= config.bin %> <%= command.id %> --password $PASSWORD --address foo@bar.example", | ||
}, | ||
{ | ||
description: "Create non-interactively with random password", | ||
command: | ||
"<%= config.bin %> <%= command.id %> --random-password --address foo@bar.example", | ||
}, | ||
]; | ||
|
||
protected async getPassword( | ||
process: ProcessRenderer, | ||
): Promise<[string, boolean]> { | ||
if (this.flags.password) { | ||
return [this.flags.password, false]; | ||
} | ||
|
||
if (this.flags["random-password"]) { | ||
const generated = await process.runStep( | ||
"generating random password", | ||
async () => { | ||
return crypto.randomBytes(32).toString("base64").substring(0, 32); | ||
}, | ||
); | ||
|
||
process.addInfo( | ||
<Text> | ||
generated password: <Value>{generated}</Value> | ||
</Text>, | ||
); | ||
return [generated, true]; | ||
} | ||
|
||
return [await process.addInput(<Text>Mailbox password</Text>, true), false]; | ||
} | ||
|
||
protected async createMailDeliverybox( | ||
projectId: string, | ||
process: ProcessRenderer, | ||
flags: OutputFlags<FlagInput<typeof Create.flags>>, | ||
): Promise<CreateResult> { | ||
const [password, passwordGenerated] = await this.getPassword(process); | ||
|
||
const response = await process.runStep( | ||
"creating mail deliverybox", | ||
async () => { | ||
const response = await this.apiClient.mail.createDeliverybox({ | ||
projectId, | ||
data: { | ||
description: flags.description, | ||
password, | ||
}, | ||
}); | ||
|
||
assertStatus(response, 201); | ||
return response; | ||
}, | ||
); | ||
|
||
await process.complete( | ||
<Success>Your mail address was successfully created.</Success>, | ||
); | ||
|
||
return { | ||
addressId: response.data.id, | ||
generatedPassword: passwordGenerated ? password : null, | ||
}; | ||
} | ||
|
||
protected async exec(): Promise<CreateResult> { | ||
const { flags } = await this.parse(Create); | ||
const projectId = await this.withProjectId(Create); | ||
|
||
const process = makeProcessRenderer( | ||
flags, | ||
"Creating a new mail deliverybox", | ||
); | ||
|
||
return this.createMailDeliverybox(projectId, process, flags); | ||
} | ||
|
||
protected render(executionResult: CreateResult): ReactNode { | ||
if (this.flags.quiet) { | ||
if (executionResult.generatedPassword) { | ||
return ( | ||
<Text> | ||
{executionResult.addressId} | ||
{"\t"} | ||
{executionResult.generatedPassword} | ||
</Text> | ||
); | ||
} | ||
return <Text>{executionResult.addressId}</Text>; | ||
} | ||
} | ||
} |