kata-cli
Version:
Kata AI Command Line Tools
549 lines (478 loc) • 21 kB
text/typescript
import { Component, JsonObject } from "merapi";
import { IHelper } from "interfaces/main";
const inquirer = require("inquirer");
const Table = require("cli-table");
const colors = require("colors");
export default class User extends Component {
constructor(private helper: IHelper, private api: any) {
super();
}
public async login(options: JsonObject) {
try {
let currToken = this.helper.getCurrentToken().token;
if (options.token) {
if (!currToken) {
currToken = options.token as string;
}
this.api.authApi.apiClient.defaultHeaders.Authorization = `Bearer ${currToken}`;
let result = await this.helper.toPromise(this.api.authApi, this.api.authApi.tokensTokenIdGet, options.token);
const tokenObj = result.data;
if (tokenObj.type === "user") {
this.setToken({ name: "user", type: tokenObj.type }, options.token as string);
} else if (tokenObj.type === "team") {
result = await this.helper.toPromise(this.api.userApi, this.api.userApi.usersUserIdGet, tokenObj.teamId);
const team = result.data;
this.setToken({ name: team.username, type: tokenObj.type }, options.token as string);
} else {
throw new Error("Invalid token");
}
} else {
let user = (options.user ? options.user : "") as string;
let pass = (options.password ? options.password : "") as string;
const answer = await inquirer.prompt([
{
type: "input",
name: "user",
message: "username: ",
when() {
return !user;
},
validate(user: string) {
if (!user) {
return "Username cannot be empty";
}
return true;
}
},
{
type: "password",
name: "password",
message: "password: ",
mask: "*",
when() {
return !pass;
},
validate(password: string) {
if (!password) {
return "Password cannot be empty";
}
return true;
}
}
]);
user = answer.user || user;
pass = answer.password || pass;
const result = await this.helper.toPromise(this.api.authApi, this.api.authApi.cliLoginPost, { username: user, password: pass });
if (!result.data.isLoggedIn && !result.data.id) {
console.log(`username or password is incorrect`);
} else {
const token = result.data.id;
this.helper.setProp("first_login", { type: "user", username: user, id: result.data.userId });
this.setToken({ name: user, type: "user", namespace: "platform" }, token);
console.log(`Logged in as ${colors.green(user)}`);
}
}
} catch (e) {
console.log(this.helper.wrapError(e));
}
}
public async logout() {
const answer = await this.helper.inquirerPrompt([
{
type: "confirm",
name: "confirmation",
message: "Do you want to log out ?",
default: false
}
]);
if (!answer.confirmation) {
return;
}
try {
const result = await this.helper.delete();
if (result) {
console.log("Logged out");
} else {
console.log("Please log in first");
}
this.helper.clearCommandSession();
} catch (e) {
console.log(this.helper.wrapError(e));
}
}
public async switch(type: string, name?: string) {
try {
const firstLogin = this.helper.getProp("first_login") as JsonObject;
const currentType = this.helper.getProp("current_user_type");
const currentLogin = this.helper.getProp("current_login");
const username = name ? name : currentLogin;
if (currentType === type && username === currentLogin) {
throw new Error(`Unable to switch : already on ${colors.green(currentLogin)} as ${colors.green(type)}`);
}
const isImpersonate = this.helper.getProp("isImpersonate");
if (type === "team") {
let userId: string;
if (isImpersonate === true) {
const currentLoginName = this.helper.getProp("current_login").toString();
userId = (await this.getUserInfo(currentLoginName)).id;
} else {
userId = firstLogin.id.toString();
}
const { response } = await this.helper.toPromise(
this.api.userApi,
this.api.userApi.usersUserIdGet,
userId
);
if (!response) {
throw new Error(`Unable to switch team: ${colors.green(name)}`);
}
const teams = response && response.body ?
response.body.teams.filter((team: any) => team.username === name) : [];
if (teams.length > 0) {
const result = await this.helper.toPromise(
this.api.authApi,
this.api.authApi.tokensPost,
{
type: "team",
teamId: teams[0].teamId
}
);
const token = result.data.id;
this.setToken({ name, type: "team" }, token);
this.helper.setProp("current_login", name);
this.helper.setProp("current_user_type", "team");
console.log(`Switched to team: ${colors.green(name)}`);
} else {
console.log(`Invalid team name. Unable to switch to team: ${colors.red(name)}`);
}
} else if (type === "user") {
if (isImpersonate === true) {
// TODO: jika user login sbg admin, impersonate dewi, switch ke team, lalu mau switch ke user yg non-user tsb
const userTokenInfo = this.getUserTokenInfo(name);
if (!userTokenInfo || userTokenInfo === undefined) {
throw new Error(`${colors.red(name)}'s token is not found.`);
} else if ( userTokenInfo.userName === "admin") {
throw new Error(`Cannot switch to ${colors.red(name)}. Use unimpersonate.`);
} else {
if (name === userTokenInfo.userName) {
this.helper.setProp("current_login", name);
this.helper.setProp("current_user_type", "user");
console.log(`Switched to user ${colors.green(name)}`);
} else {
throw new Error(`Unable to switch to user ${colors.red(name)}.`);
}
}
} else {
this.helper.setProp("current_login", firstLogin.username);
this.helper.setProp("current_user_type", "user");
console.log(`Switched to user ${colors.green(firstLogin.username)}`);
}
}
} catch (e) {
console.log(this.helper.wrapError(e));
}
}
public async changePassword() {
try {
const passObj = await this.getNewPasswordData();
if (passObj.newPass !== passObj.rePass) {
throw new Error("Invalid retype password");
}
const currentUser = this.helper.getProp("current_login") as string;
const { data } = await this.helper.toPromise(this.api.authApi, this.api.authApi.loginPost, { username: currentUser, password: passObj.oldPass });
if (data) {
const result = await this.helper.toPromise(this.api.userApi, this.api.userApi.usersUserIdPut, currentUser, { password: passObj.newPass });
console.log("Password changed");
} else {
console.log("Invalid password");
}
} catch (error) {
console.log(this.helper.wrapError(error));
}
}
public whoami(options: JsonObject) {
const currentLogin = this.helper.getProp("current_login") as string;
const currentType = this.helper.getProp("current_user_type") as string;
console.log(`Current login: ${colors.green(currentLogin)}, login type: ${colors.green(currentType)}`);
}
public async createTeam(name: string) {
try {
const currentLogin = this.helper.getProp("current_login") as string;
const currentUserType = this.helper.getProp("current_user_type") as string;
if (currentUserType !== "user") {
throw new Error("Must be on user to do this operation");
}
const { response } = await this.helper.toPromise(this.api.teamApi, this.api.teamApi.teamsPost, { username: name, password: "", roleId: "teamAdmin" });
if (response && response.body.id) {
console.log(`Team ${colors.green(name)} created !`);
} else {
console.log(`Team ${colors.red(name)} exist !`);
}
} catch (error) {
console.log(this.helper.wrapError(error));
}
}
public async createUser(username: string, options?: JsonObject) {
const password = await this.helper.inquirerPrompt([
{
type: "password",
name: "answer",
message: "password: ",
mask: "*",
default: null
}]);
const confirmPassword = await this.helper.inquirerPrompt([
{
type: "password",
name: "answer",
message: "retype password: ",
mask: "*",
default: null
}
]);
try {
if (password.answer !== confirmPassword.answer) {
throw new Error("Invalid retype password");
}
let role: string;
if (options.admin) {
role = "admin";
} else if (options.internal) {
role = "internalUser";
} else {
role = "user";
}
const { data } = await this.helper.toPromise(this.api.userApi, this.api.userApi.usersUserIdGet, username);
if (data.id) {
throw new Error(`Username ${username} exist !`);
}
const newUser = await this.helper.toPromise(this.api.userApi, this.api.userApi.usersPost, { username, password: password.answer, roleId: role });
console.log(`New user ${colors.green(newUser.data.username)} created !`);
} catch (error) {
console.log(this.helper.wrapError(error));
}
}
public async impersonate(userName: string) {
// TODO : dibuat seperti login, pake inquirer.
try {
const currentLogin: string = this.helper.getProp("current_login").toString();
if (currentLogin !== "admin") {
throw new Error(`Your login status is not superadmin. You are not authorized to impersonate a user`);
}
// set currentToken header bearer token
const currentToken: string = this.helper.getCurrentToken().token.toString();
this.api.authApi.apiClient.defaultHeaders.Authorization = `Bearer ${currentToken}`;
// get admin token
this.api.authApi.apiClient.defaultHeaders.Authorization = `Bearer ${currentToken}`;
// get user id from username
const id: string = (await this.getUserInfo(userName)).id;
const name: string = (await this.getUserInfo(userName)).name;
const email: string = (await this.getUserInfo(userName)).email;
if ( name && email ) {
// userName is user collected input
if ( userName !== name && userName !== email ) {
throw new Error(`Sorry, username is not exist.`);
}
} else {
throw new Error(`Sorry, username is not valid.`);
}
// impersonate function
const result = await this.helper.toPromise(
this.api.authApi, this.api.authApi.impersonatePost,
{
userId: id,
namespace: "platform"
}
);
// set value on .katajson
const impersonateToken: string = result.data.id.toString();
const type: string = result.data.type.toString();
this.helper.setProp("isImpersonate", true);
this.setToken({ name, type }, impersonateToken);
console.log(`Succesfully impersonate as ${colors.green(name)}`);
} catch (error) {
console.log(this.helper.wrapError(error));
}
}
// unimpersonate command
public async unimpersonate() {
try {
const userName: string = this.helper.getProp("current_login").toString();
this.helper.deleteKeyToken(userName);
const currentLogin: string = this.helper.getProp("current_login").toString();
console.log(`Succesfully unimpersonate user. Now your current login is ${colors.green(currentLogin)}`);
} catch (error) {
console.log(this.helper.wrapError(error));
}
}
private setToken(userInfo: JsonObject, token: string) {
this.helper.setProp("current_login", userInfo.name);
this.helper.setProp("current_user_type", userInfo.type);
this.helper.setProp("namespace", userInfo.namespace);
const tokenProp = (this.helper.getProp("token") || {}) as JsonObject;
tokenProp[userInfo.name as string] = token;
this.helper.setProp("token", tokenProp);
}
private getUserTokenInfo(name: string) {
const tokenProp = (this.helper.getProp("token") || {}) as JsonObject;
if (name in tokenProp) {
const userName: string = name.toString();
const token: string = tokenProp[name as string].toString();
return {
userName,
token
};
}
}
private async getUserInfo(userName: string) {
// get userId from currentlogin
const { response } = await this.helper.toPromise(
this.api.userApi,
this.api.userApi.usersGetInfoKeyGet,
userName,
);
const user = response.body;
const email: string = user.email ? user.email.toString() : "";
const name: string = user.username.toString();
const id: string = user.userId.toString();
return {
id,
name,
email,
};
}
private async getNewPasswordData(): Promise<JsonObject> {
let oldPass : string;
let newPass : string;
let rePass : string;
const answer = await inquirer.prompt([
{
type: "password",
name: "oldPass",
message: "current password: ",
mask: "*",
when() {
return !oldPass;
},
validate(user : string) {
if (!user) {
return "Password cannot be empty";
}
return true;
}
},
{
type: "password",
name: "newPass",
message: "new password: ",
mask: "*",
when() {
return !newPass;
},
validate(password: string) {
if (!password) {
return "Password cannot be empty";
}
return true;
}
},
{
type: "password",
name: "rePass",
message: "retype new password: ",
mask: "*",
when() {
return !rePass;
},
validate(password: string, answer: JsonObject) {
if (!password) {
return "Password cannot be empty";
}
if (password !== answer.newPass) {
return "Invalid retype password";
}
return true;
}
},
]);
return answer;
}
public async forgot(username: string) {
try {
const current_login = this.helper.getProp("current_login")
if (!current_login) {
const { response } = await this.helper.toPromise(this.api.authApi, this.api.authApi.forgotPost, { username });
if (response && response.body && response.body.message) {
console.log("Please check your email to reset your password.");
}
} else {
console.log(`Please log out first`);
}
} catch (e) {
console.error(this.helper.wrapError(e));
}
}
public async listTeam() {
try {
const current_login = this.helper.getProp("current_login")
if (current_login) {
const { response } = await this.helper.toPromise(this.api.userApi, this.api.userApi.usersUserIdTeamsGet, current_login);
const table = new Table({
head: ["Team Name", "Projects", "Members", "Bots"],
colWidths: [50, 15, 15, 15]
});
response.body.forEach((team: JsonObject) => {
table.push([team.username, team.projects, team.members, team.bots]);
});
console.log(table.toString());
} else {
console.log("Please log in first");
}
} catch (e) {
console.error(this.helper.wrapError(e));
}
}
public async listTeamUser(teamName?: string) {
try {
const current_login = this.helper.getProp("current_login")
if (current_login) {
const dataTeams = await this.helper.toPromise(this.api.userApi, this.api.userApi.usersUserIdTeamsGet, current_login);
const teams: object[] = dataTeams.response.body;
const choices = teams.map((team: any) => ({
name: team.username,
value: team.teamId
}));
let teamId = null
if (teamName) {
const sameName = choices.find((choice: any) => choice.name === teamName);
if (sameName) {
teamId = sameName.value
}
} else {
const choice = await inquirer.prompt([
{
type: "list",
name: "teamId",
message: "Team:",
choices: choices
}
]);
teamId = choice.teamId
}
const { response } = await this.helper.toPromise(this.api.teamApi, this.api.teamApi.teamsTeamIdUsersGet, teamId);
const table = new Table({
head: ["Username", "Role"],
colWidths: [50, 25]
});
response.body.forEach((user: JsonObject) => {
table.push([user.username, user.roleName]);
});
console.log(table.toString());
} else {
console.log("Please log in first");
}
} catch (e) {
console.error(this.helper.wrapError(e));
}
}
}