Path: blob/master/src/packages/util/db-schema/organizations.ts
5827 views
/*1Table of organizations.23WARNING: Organizations are far from actually being implemented4fully in Cocalc! I just figure defining this can't hurt to get5the ball rollowing.6*/78import { Table } from "./types";9import { checkAccountName as checkOrganizationName } from "./name-rules";1011Table({12name: "organizations",13fields: {14organization_id: {15type: "uuid",16desc: "The uuid that determines this organization",17},18created: {19type: "timestamp",20desc: "When the organization was created.",21},22deleted: {23type: "boolean",24desc: "True if this organization has been deleted.",25},26name: {27type: "string",28pg_type: "VARCHAR(39)",29desc: "The name of this organization (used for URL's). This is optional but globally unique across all organizations *and* accounts. It can be between 1 and 39 characters from a-z A-Z 0-9 - and must not start with a dash.",30},31title: {32type: "string",33pg_type: "VARCHAR(254)",34desc: "Title of this organization",35},36description: {37type: "string",38pg_type: "VARCHAR(254)",39desc: "Description of this organization.",40},41link: {42type: "string",43pg_type: "VARCHAR(254)",44desc: "Optional URL of this organization (e.g., their webpage).",45},46email_address: {47type: "string",48pg_type: "VARCHAR(254)",49desc: "Optional email address to reach this organization.",50},51api_key: {52type: "string",53desc: "Optional API key that grants full API access to all projects that this organization owns. Key is of the form 'sk_9QabcrqJFy7JIhvAGih5c6Nb', where the random part is 24 characters (base 62).",54},55profile: {56type: "map",57desc: "Information related to displaying an avatar for this organization.",58},59users: {60type: "map",61desc: "This is a map from account_id to 'owner' | 'member'.",62},63invitations: {64type: "map",65desc: "This is a map from account_id to {created:timestamp, status:'pending'|'invited'|'accepted'|'denied', emailed:timestamp}",66},67admin_account_ids: {68type: "array",69pg_type: "UUID[]",70desc: "The account_ids of the admins of this organization.",71},72},73rules: {74desc: "All organizations.",75primary_key: "organization_id",76pg_indexes: [77"(lower(title) text_pattern_ops)",78"(lower(description) text_pattern_ops)",79"api_key",80],81pg_unique_indexes: [82"LOWER(name)", // see comments for accounts table.83],84user_query: {85get: {86throttle_changes: 500,87pg_where: [{ "organization_id = $::UUID": "organization_id" }],88fields: {89organization_id: null,90email_address: null,91name: "",92title: "",93description: "",94profile: {95image: undefined,96color: undefined,97},98created: null,99},100},101set: {102fields: {103organization_id: true,104name: true,105title: true,106description: true,107profile: true,108},109required_fields: {110organization_id: true,111},112async check_hook(db, obj, account_id, _project_id, cb) {113// Check that account_id is a member of this organization114// via a db query, since otherwise no permission to do anything.115if (116!(await db.accountIsInOrganization({117account_id,118organization_id: obj["organization_id"],119}))120) {121cb(`account must be a member of the organization`);122return;123}124125if (obj["name"] != null) {126try {127checkOrganizationName(obj["name"]);128} catch (err) {129cb(err.toString());130return;131}132const id = await db.nameToAccountOrOrganization(obj["name"]);133if (id != null && id != account_id) {134cb(135`name "${obj["name"]}" is already taken by another organization or account`,136);137return;138}139}140141// Hook to truncate some text fields to at most 254 characters, to avoid142// further trouble down the line.143for (const field of ["title", "description", "email_address"]) {144if (obj[field] != null) {145obj[field] = obj[field].slice(0, 254);146}147}148cb();149},150},151},152},153});154155156