Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/account/store.ts
1503 views
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 { List, Map } from "immutable";
7
import { reduce } from "lodash";
8
9
import { store as customizeStore } from "@cocalc/frontend/customize";
10
import { make_valid_name } from "@cocalc/util/misc";
11
import { Store } from "@cocalc/util/redux/Store";
12
import { get_total_upgrades } from "@cocalc/util/upgrades";
13
import type { AccountState } from "./types";
14
15
declare var DEBUG: boolean;
16
17
// Define account store
18
export class AccountStore extends Store<AccountState> {
19
// User type
20
// - 'public' : user is not signed in at all, and not trying to sign in
21
// - 'signing_in' : user is currently waiting to see if sign-in attempt will succeed
22
// - 'signed_in' : user has successfully authenticated and has an id
23
constructor(name, redux) {
24
super(name, redux);
25
this.setup_selectors();
26
}
27
28
get_user_type(): string {
29
return this.get("user_type");
30
}
31
32
get_account_id(): string {
33
return this.get("account_id");
34
}
35
36
selectors = {
37
is_anonymous: {
38
fn: () => {
39
return is_anonymous(
40
this.get("is_logged_in"),
41
this.get("email_address"),
42
this.get("passports"),
43
this.get("lti_id"),
44
);
45
},
46
dependencies: [
47
"email_address",
48
"passports",
49
"is_logged_in",
50
"lti_id",
51
] as const,
52
},
53
is_admin: {
54
fn: () => {
55
const groups = this.get("groups");
56
return !!groups && groups.includes("admin");
57
},
58
dependencies: ["groups"] as const,
59
},
60
};
61
62
get_terminal_settings(): { [key: string]: any } | undefined {
63
return this.get("terminal") ? this.get("terminal").toJS() : undefined;
64
}
65
66
get_editor_settings(): { [key: string]: any } | undefined {
67
return this.get("editor_settings")
68
? this.get("editor_settings").toJS()
69
: undefined;
70
}
71
72
get_fullname(): string {
73
const first_name = this.get("first_name");
74
const last_name = this.get("last_name");
75
if (first_name == null && last_name == null) {
76
return "Anonymous";
77
} else if (first_name == undefined) {
78
return last_name ?? "";
79
} else if (last_name == undefined) {
80
return first_name ?? "";
81
} else {
82
return `${first_name} ${last_name}`;
83
}
84
}
85
86
get_first_name(): string {
87
return this.get("first_name", "Anonymous");
88
}
89
90
get_color(): string {
91
return this.getIn(
92
["profile", "color"],
93
this.get("account_id", "f00").slice(0, 6),
94
);
95
}
96
97
get_username(): string {
98
return make_valid_name(this.get_fullname());
99
}
100
101
get_email_address(): string | undefined {
102
return this.get("email_address");
103
}
104
105
get_confirm_close(): string {
106
return this.getIn(["other_settings", "confirm_close"]);
107
}
108
109
// Total upgrades this user is paying for (sum of all upgrades from subscriptions)
110
get_total_upgrades(): { [key: string]: number } | undefined {
111
const stripe_data = this.getIn([
112
"stripe_customer",
113
"subscriptions",
114
"data",
115
]);
116
// to fake having upgrades, type this in the console
117
// cc.redux.getStore('account').fake_upgrades = true
118
if (DEBUG && (this as any).fake_upgrades && !stripe_data) {
119
// fake debugging data
120
return get_total_upgrades({}, true);
121
}
122
return stripe_data && get_total_upgrades(stripe_data.toJS());
123
}
124
125
hasLegacyUpgrades = () => {
126
return this.getIn(["stripe_customer", "subscriptions", "data"]) != null;
127
};
128
129
// uses the total upgrades information to determine, if this is a paying member
130
// TODO: this is not used anywhere; but, if it was, it should also take into account
131
// being a license manager...
132
is_paying_member(): boolean {
133
const ups = this.get_total_upgrades();
134
return ups != null && reduce(ups, (a: number, b: number) => a + b, 0) > 0;
135
}
136
137
get_page_size(): number {
138
return this.getIn(["other_settings", "page_size"], 500);
139
}
140
141
isTourDone(tour: string): boolean {
142
const tours = this.get("tours");
143
if (!tours) return false;
144
return tours.includes(tour) || tours.includes("all");
145
}
146
147
showSymbolBarLabels(): boolean {
148
return this.getIn(["other_settings", "show_symbol_bar_labels"], false);
149
}
150
}
151
152
// A user is anonymous if they have not provided a way to sign
153
// in later (besides their cookie), i.e., if they have no
154
// passport strategies and have not provided an email address.
155
// In is_personal mode, user is never anonymous.
156
function is_anonymous(
157
is_logged_in: boolean,
158
email_address: string | undefined | null,
159
passports: Map<string, any> | undefined | null,
160
lti_id: List<string> | undefined | null,
161
): boolean {
162
if (!is_logged_in) {
163
return false;
164
}
165
if (email_address) {
166
return false;
167
}
168
if (passports != null && passports.size > 0) {
169
return false;
170
}
171
if (lti_id != null && lti_id.size > 0) {
172
return false;
173
}
174
if (customizeStore.get("is_personal")) {
175
return false;
176
}
177
return true;
178
}
179
180