CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/client/anonymous-setup.ts
Views: 687
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
import { once } from "@cocalc/util/async-utils";
7
import { redux } from "../app-framework";
8
import { QueryParams } from "../misc/query-params";
9
import { WelcomeFile } from "./welcome-file";
10
import { WebappClient } from "./client";
11
import { PROJECT_INVITE_QUERY_PARAM } from "../collaborators/handle-project-invite";
12
import { hasRememberMe } from "@cocalc/frontend/misc/remember-me";
13
import { appBasePath } from "@cocalc/frontend/customize/app-base-path";
14
15
export const ANON_PROJECT_TITLE = "Welcome to CoCalc!";
16
17
/*
18
should_do_anonymous_setup: Determine if the anonymous query param is set at all
19
(doesn't matter to what) during initial page load. Similar, if the
20
project_invite query param is set, this implies anonymous, so we also do anon
21
setup there if the user isn't already (likely) signed in.
22
23
Also do NOT make true if has_remember_me is set, since then probably
24
the user has an account.
25
*/
26
let project_invite_query_param = QueryParams.get(PROJECT_INVITE_QUERY_PARAM);
27
export function should_do_anonymous_setup(): boolean {
28
const anonymous_query_param = QueryParams.get("anonymous");
29
return (
30
(anonymous_query_param != null || project_invite_query_param != null) &&
31
!hasRememberMe(appBasePath)
32
);
33
}
34
35
async function setup_default_project(log) {
36
const actions = redux.getActions("projects");
37
log("creating project");
38
const project_id = await actions.create_project({
39
title: ANON_PROJECT_TITLE,
40
start: true,
41
description: "",
42
});
43
log("opening project");
44
actions.open_project({ project_id, switch_to: true });
45
await new WelcomeFile(project_id).open();
46
}
47
48
export async function do_anonymous_setup(client: WebappClient): Promise<void> {
49
function log(..._args): void {
50
// uncomment to debug...
51
// console.log("do_anonymous_setup", ..._args);
52
}
53
log();
54
try {
55
redux.getActions("account").setState({ doing_anonymous_setup: true });
56
log("creating account");
57
try {
58
const resp = await client.account_client.create_account({
59
first_name: "Anonymous",
60
last_name: `User-${Math.round(Date.now() / 1000)}`,
61
});
62
if (resp?.event == "account_creation_failed") {
63
throw Error(resp.error);
64
}
65
} catch (err) {
66
log("failed to create account", err);
67
// If there is an error specifically with creating the account
68
// due to the backend not allowing it (e.g., missing token), then
69
// it is fine to silently return, which falls back to the login
70
// screen. Of course, all other errors below should make some noise.
71
return;
72
}
73
if (!client.is_signed_in()) {
74
log("waiting to be signed in");
75
await once(client, "signed_in");
76
}
77
if (project_invite_query_param) {
78
// This will get handled elsewhere. In particular, we
79
// don't need to do anything else besides make
80
// their anonymous account.
81
return;
82
}
83
84
// "share" and "custom software images" create projects on their own!
85
const launch_store = redux.getStore(
86
(await import("../launch/actions")).NAME
87
);
88
const need_project = !launch_store.get("type");
89
if (need_project) {
90
await setup_default_project(log);
91
}
92
} catch (err) {
93
console.warn("ERROR doing anonymous sign up -- ", err);
94
log("err", err);
95
// There was an error creating the account (probably), so we do nothing
96
// further involving making an anonymous account.
97
// If the user didn't get signed in, this will fallback to sign in page, which
98
// is reasonable behavior.
99
// Such an error *should* happen if, e.g., a sign in token is required,
100
// or maybe this user's ip is blocked. Falling back
101
// to normal sign up makes sense in this case.
102
return;
103
} finally {
104
redux.getActions("account").setState({ doing_anonymous_setup: false });
105
log("removing anonymous param");
106
// In all cases, remove the 'anonymous' parameter. This way if
107
// they refresh their browser it won't cause confusion.
108
QueryParams.remove("anonymous");
109
}
110
}
111
112