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/next/lib/share/get-public-path-info.ts
Views: 687
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45import getPool from "@cocalc/database/pool";6import getContents, { getSizeLimit } from "./get-contents";7import getProjectInfo from "./get-project";8import { join } from "path";9import basePath from "lib/base-path";10import isCollaborator from "@cocalc/server/projects/is-collaborator";11import getAccountId from "lib/account/get-account";12import { isStarred as getIsStarred } from "@cocalc/server/public-paths/star";13import getProxiedPublicPathInfo from "lib/share/proxy/get-proxied-public-path-info";1415export default async function getPublicPathInfo({16id,17relativePath,18public_path,19req,20}: {21id: string;22relativePath?: string;23public_path?: string[];24req; // use to get account_id if necessary25}) {26if (typeof id != "string" || id.length != 40) {27throw Error("invalid id");28}2930// TODO: currently not using any caching because when editing and saving, we want info to update.31// However, we should implement this by using a query param to prevent using cache?32const pool = getPool();3334// Get the database entry that describes the public path35const { rows } = await pool.query(36`SELECT project_id, path, description, compute_image, license, disabled, unlisted,37authenticated, url, jupyter_api, redirect, created, last_edited,38counter::INT,39(SELECT COUNT(*)::INT FROM public_path_stars WHERE public_path_id=id) AS stars,40CASE WHEN site_license_id <> '' THEN TRUE ELSE FALSE END AS has_site_license41FROM public_paths WHERE vhost IS NULL AND id=$1`,42[id],43);44if (rows.length == 0 || rows[0].project_id == null || rows[0].path == null) {45throw Error("not found");46}4748if (relativePath == null) {49if (public_path?.[1] == "files") {50// only files/ implemented right now; we might add other things like edit/ later?51relativePath = public_path.slice(2).join("/");52} else {53relativePath = "";54}55}5657if (relativePath.includes("..") || relativePath.startsWith("/")) {58// a security check59throw Error("invalid relativePath");60}6162const { disabled, authenticated } = rows[0];63const account_id = await getAccountId(req);6465if (disabled) {66// Share is disabled, so account_id must be a collaborator on the project.67if (68!account_id ||69!(await isCollaborator({70account_id,71project_id: rows[0].project_id,72}))73) {74throw Error("not found");75}76}7778if (authenticated) {79// Only authenticated users are allowed to access80if (account_id == null) {81throw Error("not found");82}83}8485// if user is signed in, whether or not they stared this.86const isStarred = account_id ? await getIsStarred(id, account_id) : null;8788try {89let details;90if (rows[0].url) {91// only proxied public paths have url attribute92details = await getProxiedPublicPathInfo(rows[0].url, public_path ?? []);93if (details.contents != null) {94const limit = getSizeLimit(95public_path96? (public_path[public_path.length - 1] ?? "")97: rows[0].url,98);99if (details.contents.size > limit) {100// it would be nice to do this *BEFORE* pulling it from github, etc., but101// life is short.102details.contents.content =103"File too big to be displayed; download it instead.";104details.contents.size = details.contents.content.length;105}106}107} else {108const { title, avatar_image_full } = await getProjectInfo(109rows[0].project_id,110["title", "avatar_image_full"],111"medium",112);113details = {114contents: await getContents(115rows[0].project_id,116join(rows[0].path, relativePath),117),118projectTitle: title,119projectAvatarImage: avatar_image_full,120};121}122return {123id,124...rows[0],125relativePath,126basePath,127isStarred,128...details,129created: rows[0].created?.toISOString() ?? null,130last_edited: rows[0].last_edited?.toISOString() ?? null,131};132} catch (error) {133return {134id,135...rows[0],136relativePath,137isStarred,138created: rows[0].created?.toISOString() ?? null,139last_edited: rows[0].last_edited?.toISOString() ?? null,140error: error.toString(),141};142}143}144145146