diff --git a/server/commands/device.ts b/server/commands/device.ts new file mode 100644 index 0000000..c114a74 --- /dev/null +++ b/server/commands/device.ts @@ -0,0 +1,161 @@ +import { flags } from "@oclif/command"; +import { ux } from "cli-ux"; +import { capitalize } from "lodash"; +import { FindConditions } from "typeorm"; + +import ManageCommand from "../ManageCommand"; + +import { Input } from "@oclif/parser/lib/flags"; +import { SprinklersDevice, User } from "@server/entities"; + +type DeviceFlags = (typeof DeviceCommand)["flags"] extends Input + ? F + : never; + +type Action = "show" | "delete" | "add-user" | "remove-user"; + +const VALID_ACTIONS: Action[] = [ "show", "delete", "add-user", "remove-user" ]; + +// tslint:disable:no-shadowed-variable + +export default class DeviceCommand extends ManageCommand { + static description = "Manage devices"; + + static flags = { + show: flags.boolean({ + char: "s", + exclusive: ["add-user", "delete"], + description: "Show devices(s)", + }), + "add-user": flags.boolean({ + char: "a", + exclusive: ["show", "delete"], + description: "Add a user as owning this device (specify --username)" + }), + "remove-user": flags.boolean({ + char: "r", + exclusive: ["add-user", "show", "delete"], + description: "Remove a user as owning this device (specify --username)" + }), + delete: flags.boolean({ + char: "d", + exclusive: ["show", "add-user"], + description: "Delete a user (by --id or --username)" + }), + id: flags.integer({ + description: "The id of the device to update or delete", + }), + name: flags.string({ + description: "The name of the device, when creating or updating" + }), + deviceId: flags.string({ + description: "The deviceId of the device, when creating or updating" + }), + username: flags.string({ + description: "Specify a username for --show or --add-user" + }), + }; + + getAction(flags: DeviceFlags): Action { + for (const action of VALID_ACTIONS) { + if (flags[action]) { + return action; + } + } + const actionFlags = VALID_ACTIONS.map(action => `--${action}`); + this.error(`Must specify an action (${actionFlags.join(', ')})`, { + exit: false, + }); + return this._help(); + } + + getFindConditions(flags: DeviceFlags, action: Action): FindConditions { + let whereClause: FindConditions = {}; + if (flags.id) { + whereClause.id = flags.id; + } + if (flags.name) { + whereClause.name = flags.name; + } + if (flags.deviceId) { + whereClause.deviceId = flags.deviceId; + } + if (false) { + this.error(`Must specify --id to ${action}`, { + exit: false + }); + return this._help(); + } + return whereClause; + } + + async getOrDeleteDevice(flags: DeviceFlags, action: Action): Promise { + const findConditions = this.getFindConditions(flags, action); + if (action === "delete") { + const result = await this.database.sprinklersDevices.delete(findConditions); + if (result.raw[1] > 0) { + this.log(`Deleted device`); + } else { + this.error("Did not find device to delete"); + } + return this.exit(); + } else { + const device = await this.database.sprinklersDevices.findOne(findConditions); + if (!device) { + return this.error(`The specified device does not exist`); + } + return device; + } + } + + async run() { + const parseResult = this.parse(DeviceCommand); + + const flags = parseResult.flags; + const action = this.getAction(flags); + + await this.connect(); + + if (flags.show) { + const findConditions = this.getFindConditions(flags, action); + let query = this.database.sprinklersDevices.createQueryBuilder("device") + .leftJoinAndSelect("device.users", "user") + .where(findConditions); + if (flags.username) { + query = query.where("user.username = :username", { username: flags.username }); + } + const devices = await query.getMany(); + if (devices.length == 0) { + this.log("No sprinklers devices found"); + return 1; + } + this.log("Devices: ") + for (const device of devices) { + this.log(JSON.stringify(device, null, " ")); + } + return; + } + + const device = await this.getOrDeleteDevice(flags, action); + + if (flags["add-user"] || flags["remove-user"]) { + if (!flags.username) { + return this.error("Must specify --username for --add-user") + } + const user = await this.database.users.findByUsername(flags.username); + if (!user) { + return this.error(`Could not find user with username '${flags.username}'`); + } + let query = this.database.sprinklersDevices.createQueryBuilder() + .relation("users") + .of(device); + if (flags["add-user"]) { + await query.add(user); + this.log(`Added user '${user.username}' to device '${device.name}`); + } else { + await query.remove(user); + this.log(`Removed user '${user.username}' from device '${device.name}`); + } + } + } +} diff --git a/server/commands/user.ts b/server/commands/user.ts index 224e90f..d53c494 100644 --- a/server/commands/user.ts +++ b/server/commands/user.ts @@ -89,7 +89,6 @@ export default class UserCommand extends ManageCommand { } else { const findConditions = this.getFindConditions(flags, action); if (action === "delete") { - this.log("findConditions: ", findConditions) const result = await this.database.users.delete(findConditions); this.log(`Deleted user: `, result); return this.exit(); @@ -121,12 +120,11 @@ export default class UserCommand extends ManageCommand { } const users = await this.database.users.find({ where: whereClause }); if (users.length == 0) { - console.log("No users found"); - return 1; + this.error("No users found"); } - console.log("Users: ") + this.log("Users: ") for (const user of users) { - console.log(JSON.stringify(user.toJSON())); + this.log(JSON.stringify(user.toJSON())); } return; }