Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/frontend/client/users.ts
Views: 687
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45import { AsyncCall } from "./client";6import { User } from "../frame-editors/generic/client";7import { isChatBot, chatBotName } from "@cocalc/frontend/account/chatbot";8import api from "./api";9import TTL from "@isaacs/ttlcache";10import { reuseInFlight } from "@cocalc/util/reuse-in-flight";11import * as message from "@cocalc/util/message";1213const nameCache = new TTL({ ttl: 60 * 1000 });1415export class UsersClient {16private async_call: AsyncCall;1718constructor(_call: Function, async_call: AsyncCall) {19this.async_call = async_call;20}2122user_search = reuseInFlight(23async (opts: {24query: string;25limit?: number;26active?: string; // if given, would restrict to users active this recently27admin?: boolean; // admins can do an admin version of the query, which also does substring searches on email address (not just name)28only_email?: boolean; // search only via email address29}): Promise<User[]> => {30if (opts.limit == null) opts.limit = 20;31if (opts.active == null) opts.active = "";3233const { results } = await this.async_call({34message: message.user_search({35query: opts.query,36limit: opts.limit,37admin: opts.admin,38active: opts.active,39only_email: opts.only_email40}),41});42return results;43},44);4546// Gets username with given account_id. We use caching and aggregate to47// makes it so this never calls to the backend more than once at a time48// (per minute) for a given account_id.49get_username = reuseInFlight(50async (51account_id: string,52): Promise<{ first_name: string; last_name: string }> => {53if (isChatBot(account_id)) {54return { first_name: chatBotName(account_id), last_name: "" };55}56const v = await this.getNames([account_id]);57const u = v[account_id];58if (u == null) {59throw Error(`no user with account_id ${account_id}`);60}61return u;62},63);6465// get map from account_id to first_name, last_name (or undefined if no account); cached66// for about a minute client side.67getNames = reuseInFlight(async (account_ids: string[]) => {68const x: {69[account_id: string]:70| { first_name: string; last_name: string }71| undefined;72} = {};73const v: string[] = [];74for (const account_id of account_ids) {75if (nameCache.has(account_id)) {76x[account_id] = nameCache.get(account_id);77} else {78v.push(account_id);79}80}81if (v.length > 0) {82const { names } = await api("/accounts/get-names", { account_ids: v });83for (const account_id of v) {84// iterate over v to record accounts that don't exist too85x[account_id] = names[account_id];86nameCache.set(account_id, names[account_id]);87}88}89return x;90});91}929394