import { omit } from "lodash" ; import { PostgreSQL } from "./types" ; import { callback2 } from "@cocalc/util/async-utils" ; import { query } from "./query" ; import debug from "debug" ; const L = debug ( "hub:project-queries" ) ; import { DUMMY_SECRET } from "@cocalc/util/consts" ; import { DatastoreConfig } from "@cocalc/util/types" ; export async function project_has_network_access ( db , project_id ) { let x ; try { x = await callback2 ( db . get_project , { project_id , columns : [ "users" , "settings" ] , } ) ; } catch ( err ) { return false ; } if ( x . settings != null && x . settings . network ) { return true ; } if ( x . users != null ) { for ( const account_id in x . users ) { if ( x . users [ account_id ] != null && x . users [ account_id ] . upgrades != null && x . users [ account_id ] . upgrades . network ) { return true ; } } } return false ; } interface GetDSOpts { db : PostgreSQL ; account_id : string ; project_id : string ; } async function get_datastore ( opts ) { const { db , account_id , project_id } = opts ; const q = await query ( { db , table : "projects" , select : [ "addons" , "users" ] , where : { project_id } , one : true , } ) ; if ( q . users [ account_id ] == null ) throw Error ( `access denied` ) ; return q . addons ?. datastore ; } export async function project_datastore_set ( db , account_id , project_id , config ) { if ( config . name == null ) throw Error ( "configuration 'name' is not defined" ) ; if ( typeof config . type !== "string" ) throw Error ( "configuration 'type' is not defined (must be 'gcs', 'sshfs', ...)" ) ; for ( const [ key , val ] of Object . entries ( config ) ) { if ( typeof val !== "string" && typeof val !== "boolean" ) { throw new Error ( `Invalid value -- '${ key }' is not a valid type` ) ; } if ( typeof val === "string" && val . length > 100000 ) { throw new Error ( `Invalid value -- '${ key }' is too long` ) ; } } const old_name = config . __old_name ; const conf_new = omit ( config , "name" , "secret" , "__old_name" ) ; const ds_prev = await get_datastore ( { db , account_id , project_id } ) ; const prev_name = old_name != null ? old_name : config . name ; if ( ds_prev != null && ds_prev [ prev_name ] != null && ( config . secret === DUMMY_SECRET || config . secret === "" ) ) { conf_new . secret = ds_prev [ prev_name ] . secret ; } else { conf_new . secret = Buffer . from ( config . secret ?? "" ) . toString ( "base64" ) ; } await query ( { db , query : "UPDATE projects" , where : { "project_id = $::UUID" : project_id } , jsonb_merge : { addons : { datastore : { [ config . name ] : conf_new } } } , } ) ; } export async function project_datastore_del ( db , account_id , project_id , name ) { L ( "project_datastore_del" , name ) ; if ( typeof name !== "string" || name . length == 0 ) { throw Error ( "Datastore name not properly set." ) ; } const ds = await get_datastore ( { db , account_id , project_id } ) ; delete ds [ name ] ; await query ( { db , query : "UPDATE projects" , where : { "project_id = $::UUID" : project_id } , jsonb_set : { addons : { datastore : ds } } , } ) ; } export async function project_datastore_get ( db , account_id , project_id ) { try { const ds = await get_datastore ( { db , account_id , project_id , } ) ; if ( ds != null ) { for ( const [ k , v ] of Object . entries ( ds ) ) { ds [ k ] = omit ( v , "secret" ) as any ; } } return { addons : { datastore : ds } , } ; } catch ( err ) { return { type : "error" , error : `${ err }` } ; } }