Skip to content

Commit 682c673

Browse files
committed
Merge remote-tracking branch 'origin/master' into i18n
2 parents 1c9701c + cad9d53 commit 682c673

File tree

14 files changed

+215
-89
lines changed

14 files changed

+215
-89
lines changed

src/packages/hub/hub.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,23 @@
77
// middle of the action, connected to potentially thousands of clients,
88
// many Sage sessions, and PostgreSQL database.
99

10+
import TTLCache from "@isaacs/ttlcache";
1011
import { callback } from "awaiting";
1112
import blocked from "blocked";
1213
import { spawn } from "child_process";
1314
import { program as commander, Option } from "commander";
15+
1416
import basePath from "@cocalc/backend/base-path";
1517
import {
1618
pghost as DEFAULT_DB_HOST,
1719
pgdatabase as DEFAULT_DB_NAME,
1820
pguser as DEFAULT_DB_USER,
1921
} from "@cocalc/backend/data";
22+
import { trimLogFileSize } from "@cocalc/backend/logger";
2023
import port from "@cocalc/backend/port";
2124
import { init_start_always_running_projects } from "@cocalc/database/postgres/always-running";
25+
import { load_server_settings_from_env } from "@cocalc/database/settings/server-settings";
26+
import { init_passport } from "@cocalc/server/hub/auth";
2227
import { initialOnPremSetup } from "@cocalc/server/initial-onprem-setup";
2328
import initHandleMentions from "@cocalc/server/mentions/handle";
2429
import initProjectControl, {
@@ -28,23 +33,20 @@ import initIdleTimeout from "@cocalc/server/projects/control/stop-idle-projects"
2833
import initNewProjectPoolMaintenanceLoop from "@cocalc/server/projects/pool/maintain";
2934
import initPurchasesMaintenanceLoop from "@cocalc/server/purchases/maintenance";
3035
import initSalesloftMaintenance from "@cocalc/server/salesloft/init";
31-
import { load_server_settings_from_env } from "@cocalc/database/settings/server-settings";
3236
import { stripe_sync } from "@cocalc/server/stripe/sync";
3337
import { callback2, retry_until_success } from "@cocalc/util/async-utils";
34-
import { init_passport } from "@cocalc/server/hub/auth";
3538
import { getClients } from "./clients";
3639
import { set_agent_endpoint } from "./health-checks";
3740
import { start as startHubRegister } from "./hub_register";
3841
import { getLogger } from "./logger";
39-
import { trimLogFileSize } from "@cocalc/backend/logger";
4042
import initDatabase, { database } from "./servers/database";
4143
import initExpressApp from "./servers/express-app";
4244
import initHttpRedirect from "./servers/http-redirect";
4345
import initPrimus from "./servers/primus";
4446
import initVersionServer from "./servers/version";
47+
4548
const { COOKIE_OPTIONS } = require("./client"); // import { COOKIE_OPTIONS } from "./client";
4649
const MetricsRecorder = require("./metrics-recorder"); // import * as MetricsRecorder from "./metrics-recorder";
47-
import TTLCache from "@isaacs/ttlcache";
4850

4951
// Logger tagged with 'hub' for this file.
5052
const winston = getLogger("hub");

src/packages/hub/servers/app/next.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,20 @@
66
- ... and more?!
77
*/
88

9+
import { Application, NextFunction, Request, Response } from "express";
910
import { join } from "path";
10-
import { Application, Request, Response, NextFunction } from "express";
11+
1112
// @ts-ignore -- TODO: typescript doesn't like @cocalc/next/init (it is a js file).
1213
import initNextServer from "@cocalc/next/init";
13-
import handleRaw from "@cocalc/next/lib/share/handle-raw";
14-
import { getLogger } from "@cocalc/hub/logger";
15-
import shareRedirect from "./share-redirect";
16-
import createLandingRedirect from "./landing-redirect";
14+
1715
import basePath from "@cocalc/backend/base-path";
18-
import { database } from "../database";
16+
import { getLogger } from "@cocalc/hub/logger";
17+
import handleRaw from "@cocalc/next/lib/share/handle-raw";
1918
import { callback2 } from "@cocalc/util/async-utils";
19+
import { database } from "../database";
20+
import createLandingRedirect from "./landing-redirect";
21+
import shareRedirect from "./share-redirect";
22+
import { separate_file_extension } from "@cocalc/util/misc";
2023

2124
export default async function init(app: Application) {
2225
const winston = getLogger("nextjs");
@@ -48,18 +51,22 @@ export default async function init(app: Application) {
4851
// etc. servers is definitely too much, so we just disable this.
4952
// For serving actual raw content, the solution will be to use
5053
// a vhost.
54+
5155
// 1: The raw static server:
5256
const raw = join(shareBasePath, "raw");
5357
app.all(
5458
join(raw, "*"),
5559
(req: Request, res: Response, next: NextFunction) => {
60+
// Embedding only enabled for PDF files -- see note above
61+
const download =
62+
separate_file_extension(req.path).ext.toLowerCase() !== "pdf";
5663
try {
5764
handleRaw({
5865
...parseURL(req, raw),
5966
req,
6067
res,
6168
next,
62-
download: true /* do not change this by default -- see above. */,
69+
download,
6370
});
6471
} catch (_err) {
6572
res.status(404).end();

src/packages/hub/servers/express-app.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,37 @@
22
The main hub express app.
33
*/
44

5-
import { path as WEBAPP_PATH } from "@cocalc/assets";
6-
import basePath from "@cocalc/backend/base-path";
7-
import { path as CDN_PATH } from "@cocalc/cdn";
8-
import vhostShare from "@cocalc/next/lib/share/virtual-hosts";
9-
import { path as STATIC_PATH } from "@cocalc/static";
105
import compression from "compression";
116
import cookieParser from "cookie-parser";
127
import express from "express";
138
import ms from "ms";
149
import { join } from "path";
1510
import { parse as parseURL } from "url";
11+
import webpackDevMiddleware from "webpack-dev-middleware";
12+
import webpackHotMiddleware from "webpack-hot-middleware";
13+
14+
import { path as WEBAPP_PATH } from "@cocalc/assets";
15+
import basePath from "@cocalc/backend/base-path";
16+
import { path as CDN_PATH } from "@cocalc/cdn";
17+
import vhostShare from "@cocalc/next/lib/share/virtual-hosts";
18+
import { path as STATIC_PATH } from "@cocalc/static";
1619
import { initAnalytics } from "../analytics";
1720
import { setup_health_checks as setupHealthChecks } from "../health-checks";
1821
import { getLogger } from "../logger";
1922
import initProxy from "../proxy";
2023
import initAPI from "./app/api";
2124
import initAppRedirect from "./app/app-redirect";
22-
import initBlobs from "./app/blobs";
2325
import initBlobUpload from "./app/blob-upload";
24-
import initStripeWebhook from "./app/webhooks/stripe";
26+
import initBlobs from "./app/blobs";
2527
import initCustomize from "./app/customize";
26-
import { setupInstrumentation, initMetricsEndpoint } from "./app/metrics";
28+
import { initMetricsEndpoint, setupInstrumentation } from "./app/metrics";
2729
import initNext from "./app/next";
2830
import initSetCookies from "./app/set-cookies";
2931
import initStats from "./app/stats";
32+
import initStripeWebhook from "./app/webhooks/stripe";
3033
import { database } from "./database";
3134
import initHttpServer from "./http";
3235
import initRobots from "./robots";
33-
import webpackHotMiddleware from "webpack-hot-middleware";
34-
import webpackDevMiddleware from "webpack-dev-middleware";
3536

3637
// Used for longterm caching of files. This should be in units of seconds.
3738
const MAX_AGE = Math.round(ms("10 days") / 1000);

src/packages/next/components/path/path.tsx

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
* License: MS-RSL – see LICENSE.md for details
44
*/
55

6-
import { useEffect, useState } from "react";
76
import {
87
Alert,
98
Avatar as AntdAvatar,
@@ -13,32 +12,34 @@ import {
1312
Tooltip,
1413
} from "antd";
1514
import Link from "next/link";
16-
import PathContents from "components/share/path-contents";
17-
import PathActions from "components/share/path-actions";
18-
import LinkedPath from "components/share/linked-path";
19-
import Loading from "components/share/loading";
20-
import License from "components/share/license";
21-
import ProjectLink from "components/share/project-link";
22-
import useCounter from "lib/share/counter";
23-
import { Layout } from "components/share/layout";
24-
import { Customize } from "lib/share/customize";
25-
import type { CustomizeType } from "lib/customize";
26-
import { getTitle } from "lib/share/util";
27-
import SanitizedMarkdown from "components/misc/sanitized-markdown";
28-
import Badge from "components/misc/badge";
15+
import { useRouter } from "next/router";
16+
import { join } from "path";
17+
import { useEffect, useState } from "react";
18+
2919
import { Icon } from "@cocalc/frontend/components/icon";
3020
import {
31-
SHARE_AUTHENTICATED_ICON,
3221
SHARE_AUTHENTICATED_EXPLANATION,
22+
SHARE_AUTHENTICATED_ICON,
3323
} from "@cocalc/util/consts/ui";
34-
import apiPost from "lib/api/post";
3524
import InPlaceSignInOrUp from "components/auth/in-place-sign-in-or-up";
36-
import { useRouter } from "next/router";
37-
import type { PathContents as PathContentsType } from "lib/share/get-contents";
38-
import Avatar from "components/share/proxy/avatar";
39-
import A from "components/misc/A";
40-
import { join } from "path";
4125
import { Tagline } from "components/landing/tagline";
26+
import A from "components/misc/A";
27+
import Badge from "components/misc/badge";
28+
import SanitizedMarkdown from "components/misc/sanitized-markdown";
29+
import { Layout } from "components/share/layout";
30+
import License from "components/share/license";
31+
import LinkedPath from "components/share/linked-path";
32+
import Loading from "components/share/loading";
33+
import PathActions from "components/share/path-actions";
34+
import PathContents from "components/share/path-contents";
35+
import ProjectLink from "components/share/project-link";
36+
import Avatar from "components/share/proxy/avatar";
37+
import apiPost from "lib/api/post";
38+
import type { CustomizeType } from "lib/customize";
39+
import useCounter from "lib/share/counter";
40+
import { Customize } from "lib/share/customize";
41+
import type { PathContents as PathContentsType } from "lib/share/get-contents";
42+
import { getTitle } from "lib/share/util";
4243

4344
import { SocialMediaShareLinks } from "components/landing/social-media-share-links";
4445

src/packages/next/components/project/project.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import Loading from "components/share/loading";
1717
import { Layout } from "components/share/layout";
1818
import A from "components/misc/A";
1919
import { Customize } from "lib/share/customize";
20-
import { User } from "lib/share/types";
20+
import { ProjectCollaborator } from "lib/api/schema/projects/collaborators/list";
2121
import Edit from "./edit";
2222
import editURL from "lib/share/edit-url";
2323
import Markdown from "@cocalc/frontend/editors/slate/static-markdown";
@@ -104,7 +104,7 @@ export default function Project({
104104

105105
function isCollaborator(
106106
account: undefined | { account_id: string },
107-
collaborators: User[]
107+
collaborators: ProjectCollaborator[],
108108
): boolean {
109109
const account_id = account?.account_id;
110110
if (account_id == null) return false;

src/packages/next/components/share/collaborators.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import User from "./user";
2-
import { User as IUser } from "lib/share/types";
2+
import { ProjectCollaborator } from "lib/api/schema/projects/collaborators/list";
33

44
export default function Collaborators({
55
collaborators,
66
}: {
7-
collaborators: IUser[];
7+
collaborators: ProjectCollaborator[];
88
}) {
99
const v: JSX.Element[] = [];
1010
for (const user of collaborators ?? []) {

src/packages/next/components/share/file-contents.tsx

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,28 @@
33
* License: MS-RSL – see LICENSE.md for details
44
*/
55

6-
import { getExtension } from "lib/share/util";
6+
import Markdown from "@cocalc/frontend/editors/slate/static-markdown";
77
import {
88
isAudio,
99
isCodemirror,
10-
isImage,
1110
isHTML,
11+
isImage,
1212
isMarkdown,
1313
isVideo,
1414
} from "@cocalc/frontend/file-extensions";
15-
import rawURL from "lib/share/raw-url";
16-
import { isIOS, isSafari } from "lib/share/feature";
17-
import CodeMirror from "./codemirror";
18-
import SageWorksheet from "./sage-worksheet";
19-
import JupyterNotebook from "@cocalc/frontend/jupyter/nbviewer/nbviewer";
20-
import Markdown from "@cocalc/frontend/editors/slate/static-markdown";
21-
import Whiteboard from "@cocalc/frontend/frame-editors/whiteboard-editor/share/index";
2215
import Slides from "@cocalc/frontend/frame-editors/slides-editor/share";
16+
import Whiteboard from "@cocalc/frontend/frame-editors/whiteboard-editor/share/index";
17+
import JupyterNotebook from "@cocalc/frontend/jupyter/nbviewer/nbviewer";
18+
import { FileContext } from "@cocalc/frontend/lib/file-context";
2319
import A from "components/misc/A";
24-
import { containingPath } from "lib/share/util";
20+
import { isIOS, isSafari } from "lib/share/feature";
21+
import rawURL from "lib/share/raw-url";
2522
import getUrlTransform from "lib/share/url-transform";
26-
import getAnchorTagComponent from "./anchor-tag-component";
27-
import { FileContext } from "@cocalc/frontend/lib/file-context";
23+
import { containingPath, getExtension } from "lib/share/util";
2824
import useCustomize from "lib/use-customize";
25+
import getAnchorTagComponent from "./anchor-tag-component";
26+
import CodeMirror from "./codemirror";
27+
import SageWorksheet from "./sage-worksheet";
2928

3029
interface Props {
3130
id: string;
@@ -74,7 +73,7 @@ export default function FileContents({
7473
);
7574
} else if (isAudio(ext)) {
7675
return <audio src={raw} autoPlay={true} controls={true} loop={false} />;
77-
} else if (ext == "pdf") {
76+
} else if (ext === "pdf") {
7877
// iOS and iPADOS does not have any way to embed PDF's in pages.
7978
// I think pretty much every other web browser does, though
8079
// strangely even desktop Safari seems often broken, so we also block that.

src/packages/next/components/share/path-contents.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
* License: MS-RSL – see LICENSE.md for details
44
*/
55

6+
import { FileInfo } from "lib/share/get-contents";
67
import DirectoryListing from "./directory-listing";
78
import FileContents from "./file-contents";
8-
import { FileInfo } from "lib/share/get-contents";
99
import Loading from "./loading";
1010

1111
interface Props {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { z } from "../../../framework";
2+
3+
import { FailedAPIOperationSchema } from "../../common";
4+
5+
import { ProjectIdSchema } from "../common";
6+
7+
export const ProjectCollaboratorSchema = z.object({
8+
account_id: z.string().uuid(),
9+
first_name: z.string(),
10+
last_name: z.string(),
11+
});
12+
13+
export type ProjectCollaborator = z.infer<typeof ProjectCollaboratorSchema>;
14+
15+
// OpenAPI spec
16+
//
17+
export const ListProjectCollaboratorsInputSchema = z
18+
.object({
19+
project_id: ProjectIdSchema,
20+
})
21+
.describe(
22+
`List all collaborators on a project. When executed as an administrator, any project
23+
may be queried; otherwise, this endpoint only returns collaborators on projects for
24+
which the client account is itself a collaborator.`,
25+
);
26+
27+
export const ListProjectCollaboratorsOutputSchema = z.union([
28+
FailedAPIOperationSchema,
29+
z.array(ProjectCollaboratorSchema),
30+
]);
31+
32+
export type ListProjectCollaboratorsInput = z.infer<
33+
typeof ListProjectCollaboratorsInputSchema
34+
>;
35+
export type ListProjectCollaboratorsOutput = z.infer<
36+
typeof ListProjectCollaboratorsOutputSchema
37+
>;

src/packages/next/lib/share/get-collaborators.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,31 @@ Get the collaborators on a given project. Unlisted collaborators are NOT includ
88
*/
99

1010
import getPool from "@cocalc/database/pool";
11-
import { User } from "./types";
1211
import { isUUID } from "./util";
12+
import { ProjectCollaborator } from "../api/schema/projects/collaborators/list";
1313

1414
export default async function getCollaborators(
15-
project_id: string
16-
): Promise<User[]> {
15+
project_id: string,
16+
account_id?: string,
17+
): Promise<ProjectCollaborator[]> {
1718
if (!isUUID(project_id)) {
1819
throw Error("project_id must be a uuid");
1920
}
20-
const pool = getPool('medium');
21+
const pool = getPool("medium");
22+
let subQuery = `SELECT jsonb_object_keys(users) AS account_id FROM projects WHERE project_id=$1`;
23+
24+
const queryParams = [project_id];
25+
26+
if (account_id) {
27+
queryParams.push(account_id);
28+
subQuery += ` AND users ? $${queryParams.length}::TEXT`;
29+
}
30+
2131
const result = await pool.query(
22-
"SELECT accounts.account_id, accounts.first_name, accounts.last_name FROM accounts, (SELECT jsonb_object_keys(users) AS account_id FROM projects WHERE project_id=$1) AS users WHERE accounts.account_id=users.account_id::UUID AND accounts.unlisted IS NOT TRUE",
23-
[project_id]
32+
`SELECT accounts.account_id, accounts.first_name, accounts.last_name FROM accounts, (${subQuery})
33+
AS users WHERE accounts.account_id=users.account_id::UUID
34+
AND accounts.unlisted IS NOT TRUE`,
35+
queryParams,
2436
);
2537
return result.rows;
2638
}

0 commit comments

Comments
 (0)