Skip to content

Commit 2962472

Browse files
committed
Merge branch 'refs/heads/feat-multiple-accounts-and-instances' into feat-push-pull-all
# Conflicts: # templates/cli/lib/commands/pull.js.twig # templates/cli/lib/commands/push.js.twig # templates/cli/lib/questions.js.twig
2 parents 3d36787 + 705647d commit 2962472

File tree

9 files changed

+706
-273
lines changed

9 files changed

+706
-273
lines changed

templates/cli/index.js.twig

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ const { version } = require("./package.json");
1111
const { commandDescriptions, cliConfig } = require("./lib/parser");
1212
const { client } = require("./lib/commands/generic");
1313
{% if sdk.test != "true" %}
14-
const { login, logout, whoami } = require("./lib/commands/generic");
14+
const { login, logout, whoami, migrate } = require("./lib/commands/generic");
1515
const { init } = require("./lib/commands/init");
1616
const { pull } = require("./lib/commands/pull");
1717
const { push } = require("./lib/commands/push");
18+
{% else %}
19+
const { migrate } = require("./lib/commands/generic");
1820
{% endif %}
1921
{% for service in spec.services %}
2022
const { {{ service.name | caseLower }} } = require("./lib/commands/{{ service.name | caseLower }}");
@@ -29,12 +31,30 @@ program
2931
.version(version, "-v, --version")
3032
.option("--verbose", "Show complete error log")
3133
.option("--json", "Output in JSON format")
34+
.hook('preAction', migrate)
35+
.option("-f,--force", "Flag to confirm all warnings")
36+
.option("-a,--all", "Flag to push all resources")
37+
.option("--id [id...]", "Flag to pass list of ids for a giving action")
38+
.option("--report", "Enable reporting when cli is crashing")
3239
.on("option:json", () => {
3340
cliConfig.json = true;
3441
})
3542
.on("option:verbose", () => {
3643
cliConfig.verbose = true;
3744
})
45+
.on("option:report", function() {
46+
cliConfig.report = true;
47+
cliConfig.reportData = { data: this };
48+
})
49+
.on("option:force", () => {
50+
cliConfig.force = true;
51+
})
52+
.on("option:all", () => {
53+
cliConfig.all = true;
54+
})
55+
.on("option:id", function() {
56+
cliConfig.ids = this.opts().id;
57+
})
3858
.showSuggestionAfterError()
3959
{% if sdk.test != "true" %}
4060
.addCommand(whoami)

templates/cli/lib/commands/generic.js.twig

Lines changed: 132 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,75 @@
11
const inquirer = require("inquirer");
22
const { Command } = require("commander");
33
const Client = require("../client");
4-
const { sdkForConsole } = require("../sdks");
4+
const { sdkForConsole, questionGetEndpoint } = require("../sdks");
55
const { globalConfig, localConfig } = require("../config");
6-
const { actionRunner, success, parseBool, commandDescriptions, error, parse, drawTable } = require("../parser");
6+
const { actionRunner, success, parseBool, commandDescriptions, error, parse, log, drawTable } = require("../parser");
7+
const ID = require("../id");
78
{% if sdk.test != "true" %}
8-
const { questionsLogin, questionsListFactors, questionsMfaChallenge } = require("../questions");
9+
const { questionsLogin, questionsLogout, questionsListFactors, questionsMfaChallenge } = require("../questions");
910
const { accountUpdateMfaChallenge, accountCreateMfaChallenge, accountGet, accountCreateEmailPasswordSession, accountDeleteSession } = require("./account");
1011

11-
const loginCommand = async () => {
12-
const answers = await inquirer.prompt(questionsLogin)
12+
const DEFAULT_ENDPOINT = 'https://cloud.appwrite.io/v1';
1313

14-
let client = await sdkForConsole(false);
14+
const loginCommand = async ({ selfHosted, email, password, endpoint, mfa, code }) => {
15+
const answers = email && password ? { email, password } : await inquirer.prompt(questionsLogin);
1516

16-
await accountCreateEmailPasswordSession({
17-
email: answers.email,
18-
password: answers.password,
19-
parseOutput: false,
20-
sdk: client
21-
})
17+
if (answers.method === 'select') {
18+
const accountId = answers.accountId;
19+
20+
if (!globalConfig.getLoginIds().includes(accountId)) {
21+
throw Error('Login ID not found');
22+
}
23+
24+
globalConfig.setCurrentLogin(accountId);
25+
success(`Current account is ${accountId}`);
26+
27+
return;
28+
}
29+
30+
const oldCurrent = globalConfig.getCurrentLogin();
31+
const id = ID.unique();
2232

23-
client.setCookie(globalConfig.getCookie());
33+
globalConfig.setCurrentLogin(id);
34+
globalConfig.addLogin(id, {});
35+
globalConfig.setEmail(answers.email);
36+
globalConfig.setEndpoint(DEFAULT_ENDPOINT);
37+
38+
if (selfHosted) {
39+
const selfHostedAnswers = endpoint ? { endpoint } : await inquirer.prompt(questionGetEndpoint);
40+
41+
globalConfig.setEndpoint(selfHostedAnswers.endpoint);
42+
}
43+
44+
let client = await sdkForConsole(false);
2445

2546
let account;
2647

2748
try {
49+
await accountCreateEmailPasswordSession({
50+
email: answers.email,
51+
password: answers.password,
52+
parseOutput: false,
53+
sdk: client
54+
})
55+
56+
client.setCookie(globalConfig.getCookie());
57+
2858
account = await accountGet({
2959
sdk: client,
3060
parseOutput: false
3161
});
32-
} catch(error) {
62+
} catch (error) {
3363
if (error.response === 'user_more_factors_required') {
34-
const { factor } = await inquirer.prompt(questionsListFactors);
64+
const { factor } = mfa ? { factor: mfa } : await inquirer.prompt(questionsListFactors);
3565

3666
const challenge = await accountCreateMfaChallenge({
3767
factor,
3868
parseOutput: false,
3969
sdk: client
4070
});
4171

42-
const { otp } = await inquirer.prompt(questionsMfaChallenge);
72+
const { otp } = code ? { otp: code } : await inquirer.prompt(questionsMfaChallenge);
4373

4474
await accountUpdateMfaChallenge({
4575
challengeId: challenge.$id,
@@ -53,6 +83,8 @@ const loginCommand = async () => {
5383
parseOutput: false
5484
});
5585
} else {
86+
globalConfig.removeLogin(id);
87+
globalConfig.setCurrentLogin(oldCurrent);
5688
throw error;
5789
}
5890
}
@@ -100,20 +132,21 @@ const whoami = new Command("whoami")
100132
drawTable(data)
101133
}));
102134

103-
104135
const login = new Command("login")
105136
.description(commandDescriptions['login'])
137+
.option(`-sh, --self-hosted`, `Flag for enabling custom endpoint for self hosted instances`)
138+
.option(`--email [email]`, `User email`)
139+
.option(`--password [password]`, `User password`)
140+
.option(`--endpoint [endpoint]`, `Appwrite endpoint for self hosted instances`)
141+
.option(`--mfa [factor]`, `Multi-factor authentication login factor: totp, email, phone or recoveryCode`)
142+
.option(`--code [code]`, `Multi-factor code`)
106143
.configureHelp({
107144
helpWidth: process.stdout.columns || 80
108145
})
109146
.action(actionRunner(loginCommand));
110147

111-
const logout = new Command("logout")
112-
.description(commandDescriptions['logout'])
113-
.configureHelp({
114-
helpWidth: process.stdout.columns || 80
115-
})
116-
.action(actionRunner(async () => {
148+
const singleLogout = async (accountId) => {
149+
try {
117150
let client = await sdkForConsole();
118151

119152
await accountDeleteSession({
@@ -122,8 +155,51 @@ const logout = new Command("logout")
122155
sdk: client
123156
})
124157

125-
globalConfig.setCookie("");
126-
success()
158+
globalConfig.removeLogin(accountId);
159+
} catch (e) {
160+
error('Unable to log out, removing locally saved session information')
161+
}
162+
globalConfig.removeLogin(accountId);
163+
}
164+
165+
const logout = new Command("logout")
166+
.description(commandDescriptions['logout'])
167+
.configureHelp({
168+
helpWidth: process.stdout.columns || 80
169+
})
170+
.action(actionRunner(async () => {
171+
const logins = globalConfig.getLogins();
172+
const current = globalConfig.getCurrentLogin();
173+
174+
if (current === '') {
175+
return;
176+
}
177+
if (logins.length === 1) {
178+
await singleLogout(current);
179+
success();
180+
181+
return;
182+
}
183+
184+
const answers = await inquirer.prompt(questionsLogout);
185+
186+
if (answers.accounts) {
187+
for (let accountId of answers.accounts) {
188+
globalConfig.setCurrentLogin(accountId);
189+
await singleLogout(accountId);
190+
}
191+
}
192+
193+
const leftLogins = globalConfig.getLogins();
194+
195+
if (leftLogins.length > 0 && leftLogins.filter(login => login.id === current).length !== 1) {
196+
const accountId = leftLogins[0].id;
197+
globalConfig.setCurrentLogin(accountId);
198+
199+
success(`Current account is ${accountId}`);
200+
}
201+
202+
success();
127203
}));
128204
{% endif %}
129205

@@ -156,6 +232,7 @@ const client = new Command("client")
156232

157233
if (endpoint !== undefined) {
158234
try {
235+
const id = ID.unique();
159236
let url = new URL(endpoint);
160237
if (url.protocol !== "http:" && url.protocol !== "https:") {
161238
throw new Error();
@@ -170,7 +247,8 @@ const client = new Command("client")
170247
if (!response.version) {
171248
throw new Error();
172249
}
173-
250+
globalConfig.setCurrentLogin(id);
251+
globalConfig.addLogin(id, {});
174252
globalConfig.setEndpoint(endpoint);
175253
} catch (_) {
176254
throw new Error("Invalid endpoint or your Appwrite server is not running as expected.");
@@ -190,22 +268,45 @@ const client = new Command("client")
190268
}
191269

192270
if (reset !== undefined) {
193-
globalConfig.setEndpoint("");
194-
globalConfig.setKey("");
195-
globalConfig.setCookie("");
196-
globalConfig.setSelfSigned("");
197-
localConfig.setProject("", "");
271+
const logins = globalConfig.getLogins();
272+
273+
for (let accountId of logins.map(login => login.id)) {
274+
globalConfig.setCurrentLogin(accountId);
275+
await singleLogout(accountId);
276+
}
198277
}
199278

200279
success()
201280
}));
202281

282+
const migrate = async () => {
283+
if (!globalConfig.has('endpoint') || !globalConfig.has('cookie')) {
284+
return;
285+
}
286+
287+
const endpoint = globalConfig.get('endpoint');
288+
const cookie = globalConfig.get('cookie');
289+
290+
const id = ID.unique();
291+
const data = {
292+
endpoint,
293+
cookie,
294+
email: 'legacy'
295+
};
296+
297+
globalConfig.addLogin(id, data);
298+
globalConfig.setCurrentLogin(id);
299+
globalConfig.delete('endpoint');
300+
globalConfig.delete('cookie');
301+
302+
}
203303
module.exports = {
204304
{% if sdk.test != "true" %}
205305
loginCommand,
206306
whoami,
207307
login,
208308
logout,
209309
{% endif %}
310+
migrate,
210311
client
211312
};

0 commit comments

Comments
 (0)