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/course/sync.ts
Views: 687
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45// Describes how the client course editor syncs with the database67import { fromJS } from "immutable";8import { callback2 } from "@cocalc/util/async-utils";910// SMC libraries11import * as misc from "@cocalc/util/misc";12import { webapp_client } from "../webapp-client";13import { SyncDB } from "@cocalc/sync/editor/db/sync";14import { CourseActions } from "./actions";15import { CourseStore } from "./store";16import { AppRedux } from "../app-framework";1718export function create_sync_db(19redux: AppRedux,20actions: CourseActions,21store: CourseStore,22filename: string,23): SyncDB {24if (redux == null || actions == null || store == null) {25// just in case non-typescript code uses this...26throw Error("redux, actions and store must not be null");27}2829const project_id = store.get("course_project_id");30const path = store.get("course_filename");31actions.setState({ loading: true });3233const syncdb = webapp_client.sync_client.sync_db({34project_id,35path,36primary_keys: ["table", "handout_id", "student_id", "assignment_id"],37string_cols: ["note", "description", "title", "email_invite"],38change_throttle: 500, // helps when doing a lot of assign/collect, etc.39});4041syncdb.once("error", (err) => {42if (!actions.is_closed()) {43actions.set_error(err);44}45console.warn(`Error using '${store.get("course_filename")}' -- ${err}`);46});4748syncdb.once("ready", async () => {49const i = store.get("course_filename").lastIndexOf(".");50const t = {51settings: {52title: store.get("course_filename").slice(0, i),53description: "No description",54allow_collabs: true,55},56assignments: {},57students: {},58handouts: {},59loading: false,60};61for (const x of syncdb.get().toJS()) {62if (x.table === "settings") {63misc.merge(t.settings, misc.copy_without(x, "table"));64} else if (x.table === "students") {65t.students[x.student_id] = misc.copy_without(x, "table");66} else if (x.table === "assignments") {67t.assignments[x.assignment_id] = misc.copy_without(x, "table");68} else if (x.table === "handouts") {69t.handouts[x.handout_id] = misc.copy_without(x, "table");70}71}72for (const k in t) {73const v = t[k];74t[k] = fromJS(v);75}76if (!actions.is_closed()) {77(actions as any).setState(t); // TODO: as any since t is an object, not immutable.js map...78}79syncdb.on("change", (changes) => {80if (!actions.is_closed()) {81actions.syncdb_change(changes);82}83});8485syncdb.on("after-change", () =>86redux.getProjectActions(project_id).flag_file_activity(filename),87);8889const course_project_id = store.get("course_project_id");90const p = redux.getProjectActions(course_project_id);91if (p != null) {92p.log_opened_time(store.get("course_filename"));93}9495// Wait until the projects store has data about users of our project before configuring anything.96const projects_store = redux.getStore("projects");97try {98await callback2(projects_store.wait, {99until(p_store) {100return p_store.get_users(project_id) != null;101},102timeout: 60,103});104} catch (err) {105return; // something is very broken (or maybe admin view)...106}107if (actions.is_closed()) {108return;109}110// compute image default setup111const course_compute_image = store.getIn(["settings", "custom_image"]);112const inherit_compute_image =113store.getIn(["settings", "inherit_compute_image"]) ?? true;114// if the compute image isn't set or should be inherited, we configure it for all controlled projects115if (course_compute_image == null || inherit_compute_image) {116const course_project_compute_image = projects_store.getIn([117"project_map",118course_project_id,119"compute_image",120]);121actions.set({122custom_image: course_project_compute_image,123inherit_compute_image,124table: "settings",125});126}127128// datastore default setup129const datastore = store.getIn(["settings", "datastore"]);130if (datastore == null) {131actions.set({132datastore: true,133table: "settings",134});135}136137await actions.configuration.configure_all_projects();138139// Also140projects_store.on(141"change",142actions.handle_projects_store_update.bind(actions),143);144actions.handle_projects_store_update(projects_store);145146// Handle deprecation147if (store.getIn(["settings", "nbgrader_grade_in_instructor_project"])) {148actions.set({149nbgrader_grade_in_instructor_project: false,150nbgrader_grade_project: course_project_id,151table: "settings",152});153}154});155156return syncdb;157}158159160