diff --git a/docker_medley/Dockerfile_medley b/docker_medley/Dockerfile_medley index 7ddefac6..89e0e8ef 100644 --- a/docker_medley/Dockerfile_medley +++ b/docker_medley/Dockerfile_medley @@ -114,6 +114,9 @@ COPY scripts/* ${ONLINE_BINDIR} RUN chmod ugo+x ${ONLINE_BINDIR}/* \ && ln -s ${ONLINE_BINDIR}/request_new_tab.sh ${ONLINE_BINDIR}/request_new_tab +# copy online-specific files into medley/library +COPY --chown=${USER_NAME}:${USER_NAME} library/ONLINEUTILS ${MEDLEY_INSTALLDIR}/library +COPY --chown=${USER_NAME}:${USER_NAME} library/ONLINEUTILS.LCOM ${MEDLEY_INSTALLDIR}/library # copy INIT file into home directory COPY --chown=${USER_NAME}:${USER_NAME} init/INIT ${MEDLEY_USERDIR} diff --git a/docker_medley/init/ONLINE-INIT b/docker_medley/init/ONLINE-INIT old mode 100755 new mode 100644 index f1de5c98..666b8d77 --- a/docker_medley/init/ONLINE-INIT +++ b/docker_medley/init/ONLINE-INIT @@ -1,10 +1,13 @@ (DEFINE-FILE-INFO PACKAGE "INTERLISP" READTABLE "INTERLISP" BASE 10) -(FILECREATED "18-Mar-2025 22:45:51" {DSK}medley>il>ONLINE-INIT.;1 10668 +(FILECREATED "18-Nov-2025 23:19:56" {DSK}frank>il>online>docker_medley>init>ONLINE-INIT.;51 10938 - :EDIT-BY "guest" + :EDIT-BY "FGH" - :PREVIOUS-DATE "17-Mar-2025 17:06:18" {DSK}medley>il>ONLINE-INIT.;1) + :CHANGES-TO (VARS ONLINE-INITCOMS) + + :PREVIOUS-DATE "29-Oct-2025 23:56:02" +{DSK}frank>il>online>docker_medley>init>ONLINE-INIT.;50) (PRETTYCOMPRINT ONLINE-INITCOMS) @@ -14,6 +17,8 @@ APPS-INIT) (FILES (SYSLOAD) VTCHAT) + (FILES (SYSLOAD) + ONLINEUTILS) (GLOBALVARS Online.LogoutTimeout Online.SftpPort Online.SftpPassword Online.SftpDisplay IDLE.PROFILE IDLE.BOUNCING.BOX Online.SftpDisplayMenu ONLINEP ShellBrowser ShellOpener CLHS.OPENER MEDLEYDIR) @@ -30,6 +35,9 @@ (FILESLOAD (SYSLOAD) VTCHAT) + +(FILESLOAD (SYSLOAD) + ONLINEUTILS) (DECLARE%: DOEVAL@COMPILE DONTCOPY (GLOBALVARS Online.LogoutTimeout Online.SftpPort Online.SftpPassword Online.SftpDisplay IDLE.PROFILE @@ -149,6 +157,8 @@ (Online.DoInit [LAMBDA NIL + (* ;; "Edited 29-Oct-2025 23:55 by FGH") + (* ;; "Edited 16-Mar-2025 23:26 by guest") (* ;; "Edited 25-Feb-2024 11:37 by fgh") @@ -217,14 +227,15 @@ (RPLACA (CAR CHAT.DISPLAYTYPES) NIL) - (* ;; - "Setup NOTECARDSDIRECTORIES. Should be done it APPS-INIT. But until thats done, we'll do it here.") + (* ;; "Create File Import/Export Button") - (Online.SetUpNOTECARDSDIRECTORIES) + (Online.FileButton) - (* ;; "Create File Import/Export Button") + (* ;; "If there is a start-script file, load it ") - (Online.FileButton]) + (LET [(START-SCRIPT (UNIX-GETENV 'START_SCRIPT] + (IF START-SCRIPT + THEN (LOAD START-SCRIPT]) (ONLINEP [LAMBDA NIL (* ; "Edited 24-Feb-2024 22:31 by fgh") @@ -239,7 +250,7 @@ (BKSYSBUF " ") ) (DECLARE%: DONTCOPY - (FILEMAP (NIL (1640 10532 (Online.SftpInitInfo 1650 . 2523) (Online.SftpUpdateInfo 2525 . 2780) ( -Online.SetUpNOTECARDSDIRECTORIES 2782 . 4490) (Online.FileButton 4492 . 7320) (Online.DoInit 7322 . -10393) (ONLINEP 10395 . 10530))))) + (FILEMAP (NIL (1828 10802 (Online.SftpInitInfo 1838 . 2711) (Online.SftpUpdateInfo 2713 . 2968) ( +Online.SetUpNOTECARDSDIRECTORIES 2970 . 4678) (Online.FileButton 4680 . 7508) (Online.DoInit 7510 . +10663) (ONLINEP 10665 . 10800))))) STOP diff --git a/docker_medley/init/ONLINE-INIT.LCOM b/docker_medley/init/ONLINE-INIT.LCOM old mode 100755 new mode 100644 index c4462eba..ef9c00fb Binary files a/docker_medley/init/ONLINE-INIT.LCOM and b/docker_medley/init/ONLINE-INIT.LCOM differ diff --git a/docker_medley/library/ONLINEUTILS b/docker_medley/library/ONLINEUTILS new file mode 100644 index 00000000..1a1bd6ad --- /dev/null +++ b/docker_medley/library/ONLINEUTILS @@ -0,0 +1,47 @@ +(DEFINE-FILE-INFO PACKAGE "INTERLISP" READTABLE "INTERLISP" BASE 10) + +(FILECREATED "18-Nov-2025 22:54:33" {DSK}frank>il>medley>library>ONLINEUTILS.;2 2078 + + :EDIT-BY "FGH" + + :CHANGES-TO (FNS ShellHttpGet) + + :PREVIOUS-DATE "18-Nov-2025 22:48:48" {DSK}frank>il>medley>library>ONLINEUTILS.;1) + + +(PRETTYCOMPRINT ONLINEUTILSCOMS) + +(RPAQQ ONLINEUTILSCOMS ((FNS ShellHttpGet))) +(DEFINEQ + +(ShellHttpGet + [LAMBDA (URL OUTFILENAME) (* ; "Edited 18-Nov-2025 22:54 by FGH") + + (* ;; "Download a file specified by URL from the internet and place it in anew file name OUTFILENAME. OUTFILENAME will be versioned if it is on a versioned file device. Protocol of URL must be http: or https:. Uses wget (if it exists) or curl (if it exists) via a ShellCommand. It is an error if the underlying system doesn't have either wget or curl.") + (* ; "Edited 18-Nov-2025 22:39 by FGH") + (LET ((UURL (U-CASE URL))) + (if (NOT (OR (STRPOS "HTTP:://" UURL NIL NIL T) + (STRPOS "HTTPS://" UURL NIL NIL T))) + then (ERROR "ShellHttpGet URL argument is not a HTTP:// or HTTPS:// Url"))) + (LET* ((WGET (ShellWhich "wget")) + (CURL (if (NULL WGET) + then (ShellWhich "curl") + else NIL)) + (OUTNAME (OUTFILEP OUTFILENAME)) + (TMPFILE (CONCAT "/tmp/wget" (CLOCK))) + (UNIXFILE (CONCAT "{UNIX}" TMPFILE)) + (CMD (if WGET + then (CONCAT WGET " " URL " -O " TMPFILE) + elseif CURL + then (CONCAT CURL " " URL " --output " TMPFILE) + else NIL))) + (if (NULL CMD) + then (ERROR "ShellHttpGet - neither wget nor curl are available on this system")) + (ShellCommand CMD) + (COPYFILE UNIXFILE OUTNAME) + (DELFILE UNIXFILE) + OUTNAME]) +) +(DECLARE%: DONTCOPY + (FILEMAP (NIL (414 2055 (ShellHttpGet 424 . 2053))))) +STOP diff --git a/docker_medley/library/ONLINEUTILS.LCOM b/docker_medley/library/ONLINEUTILS.LCOM new file mode 100644 index 00000000..29b16331 Binary files /dev/null and b/docker_medley/library/ONLINEUTILS.LCOM differ diff --git a/docker_medley/scripts/run-online-medley b/docker_medley/scripts/run-online-medley index c2befdaa..b6850f7d 100755 --- a/docker_medley/scripts/run-online-medley +++ b/docker_medley/scripts/run-online-medley @@ -67,6 +67,20 @@ if [ $# -gt 1 ] && [ "$2" = "custom" ]; then fi fi # +unset START_SCRIPT +if [ -n "${START_SCRIPT_URL}" ] +then + export START_SCRIPT="${MEDLEY_USERDIR}/initdir/START-SCRIPT" + mkdir -p "$(dirname "${START_SCRIPT}")" + wget "${START_SCRIPT_URL}" -O "${START_SCRIPT}" + if [ $? -ne 0 ] + then + rm -f "${START_SCRIPT}" + unset START_SCRIPT + fi +fi +unset START_SCRIPT_URL +# if [ $# -gt 2 ]; then width=$3 else diff --git a/docs/Demo_mode.md b/docs/Demo_mode.md new file mode 100644 index 00000000..f673e2d7 --- /dev/null +++ b/docs/Demo_mode.md @@ -0,0 +1,74 @@ + +# Online.Interlisp.Org: Demo mode (aka Museum Mode) +## Overview + +When accessing online.interlisp.org (OIO) using Demo Mode, Online Medley will LOAD a Lisp file called a *start script*. The start script is specified by a query parameter in the URL through which OIO was accessed. Before the Online Medley run starts, the start script file is downloaded using ```wget```into a known file in the Medley file system. It is then LOADed as the last step in the ONLINE-INIT initialization. The intent is that upon LOAD the start script will run a demo by defining and/or LOADing additional Lisp code and then starting up that demo, e.g., via a P file package command. + +An addition aspect of Demo Mode is that login processing can (optionally) be skipped, the user automatically logged in as guest, and the Online Medley session started with no user interaction required. Alternatively, the login process can remain but the standard "Run Medley" page will be skipped and the user will go directly from login to the running Medley without having to set all the run parameters in the Run Medley page. Automatic guest login is sufficient for most demos. But requiring login allows demos to save files and context between runs of Online Medley, which is not possible with guest login. + +## Demo mode URLs +To access Demo mode, use the following URLs: + +```https://online.interlisp.og/demo?start=\``` for automatic guest login. + +```https://online.interlisp.og/demo/login?start=\``` to require logins + +`````` is a URL pointing to a start-script lisp file that can be wget'd by the OIO server. **This URL must be encoded using the equivalent of Javascript's *encodeURIComponent*.** The easiest way to do this is via one of the many websites that offer this service such as https://meyerweb.com/eric/tools/dencoder/. + +In addition to the *start* query parameter, Demo mode supports the *notecards=1* and *rooms=1* query parameters. If these query parameters are included in the Demo mode URL, then NoteCards and/or Rooms will be automatically started when Online Medley runs, in addition to the start-script. + +Any of the query parameters (start, notecards, rooms) can be left off, with the expected change of function. For example, https://online.interlisp.org/demo?notecards=1 will automatically login as guest and start notecards - but not run any start script. + +Example Demo mode URL: https://online.interlisp.org/demo?start=https%3A%2F%2Fgithub.com%2FInterlisp%2Fonline%2Fraw%2Frefs%2Fheads%2Ffgh_museum-mode%2Fstart-scripts%2FSTART-INSPHEX.LCOM¬ecards=1. This URL will automatically login as guest, wget and LOAD the file START-INSPHEX.LCOM from the Interlisp/Online repo on github and start Notecards. + +## Start scripts + +Any LOADable Lisp file (source or compiled, Interlisp or Medley CommonLisp) can serve as a start script. + +Sample start scripts can be found in the Interlisp/Online Github repo in the start-scripts directory. + +Most demos will require Lisp (or other) files that are not included in the standard Online Medley image. One very handy function to be used in start scripts for these demos is ```(ShellHttpGet URL OUTFILE)```. This function will download (using wget or curl) the file specified by URL and store it in the versioned Online Medley file system under the name OUTFILE. OUTFILE can then be LOADed by the start script. + +Below is the start script for a demo of Pamoroso's INSPHEX utility. The start script defines and then runs a function called START-INSPHEX. The START-INPHEX function in turn uses ShellHttpGet to download the source code to INSPHEX from Github, compiles it, loads the compiled file and then uses ADD.PROCESS to run the main HEXDUMP function. There is some additional complication in the call to ADD.PROCESS to ensure that packages are handled correctly. But most existing Interlisp demos will not need this complexity since they don't use packages. + +``` +(DEFINE-FILE-INFO ^^PACKAGE "INTERLISP" ^^READTABLE "INTERLISP" ^^BASE 10) + +(FILECREATED "16-Nov-2025 21:15:14" {DSK}frank>il>START-INSPHEX.;1 1641) + +(PRETTYCOMPRINT START-INSPHEXCOMS) + +(RPAQQ START-INSPHEXCOMS ((FNS START-INSPHEX) + (P (START-INSPHEX)))) +(DEFINEQ + +(START-INSPHEX + [LAMBDA NIL + (LET* ((INSPHEX.FILE (OUTFILEP "{CORE}INSPHEX")) + INSPHEX.DFASL) + (ShellHttpGet "https://raw.githubusercontent.com/pamoroso/insphex/refs/heads/main/INSPHEX" + INSPHEX.FILE) + (SETQ INSPHEX.DFASL (CL:COMPILE-FILE INSPHEX.FILE)) + (LOAD INSPHEX.DFASL) + (ADD.PROCESS (LIST (CL:FIND-SYMBOL "HEXDUMP" "INSPHEX") + (KWOTE INSPHEX.DFASL) + '(CREATEW (CREATEREGION (FIX (TIMES 0.35 SCREENWIDTH)) + (FIX (TIMES 0.25 SCREENHEIGHT)) + (FIX (TIMES 0.5 SCREENWIDTH)) + (FIX (TIMES 0.5 SCREENHEIGHT]) +) +(START-INSPHEX) +STOP + +``` + +## Start scripts outside of Demo mode + +Start scripts can also be used outside of Demo mode. In the normal OIO workflow, the user will be taken to the "Run Medley" page. On the Run Medley page, if you enable *Show advanced options* there will be a field into which you can enter the URL for a start-script (in either original or URI encoded forms). When Online Medley starts up, the specified start script will be wget'd and LOADed as in Demo mode. + +Additionally, if a ```start=``` query parameter is included in the URL used to access OIO (outside of Demo mode), then the specified URL (decoded) will be prepopulated into the Advanced Options/Start URL field on the Run Medley page. + +## Synonyms for *https::online.interlisp.org/demo* + +For legacy reasons, ```https://online.interlisp.org/demo/guest``` and ```https://online.interlisp.org/guest``` are synonyms for ```https://online.interlisp.org/demo```. + diff --git a/start-scripts/START-INSPHEX b/start-scripts/START-INSPHEX new file mode 100644 index 00000000..65c99154 --- /dev/null +++ b/start-scripts/START-INSPHEX @@ -0,0 +1,41 @@ +(DEFINE-FILE-INFO PACKAGE "INTERLISP" READTABLE "INTERLISP" BASE 10) + +(FILECREATED "18-Nov-2025 23:40:40" {DSK}frank>il>online>start-scripts>START-INSPHEX.;25 1665 + + :EDIT-BY "FGH" + + :CHANGES-TO (FNS START-INSPHEX) + (VARS START-INSPHEXCOMS) + + :PREVIOUS-DATE "11-Nov-2025 23:54:22" {DSK}frank>il>online>start-scripts>START-INSPHEX.;18 +) + + +(PRETTYCOMPRINT START-INSPHEXCOMS) + +(RPAQQ START-INSPHEXCOMS ((FNS START-INSPHEX) + (P (START-INSPHEX)))) +(DEFINEQ + +(START-INSPHEX + [LAMBDA NIL (* ; "Edited 18-Nov-2025 23:40 by FGH") + (* ; "Edited 11-Nov-2025 23:54 by FGH") + (* ; "Edited 7-Nov-2025 10:43 by FGH") + (LET* ((INSPHEX.FILE (OUTFILEP "{CORE}INSPHEX")) + INSPHEX.DFASL) + (ShellHttpGet "https://raw.githubusercontent.com/pamoroso/insphex/refs/heads/main/INSPHEX" + INSPHEX.FILE) + (SETQ INSPHEX.DFASL (CL:COMPILE-FILE INSPHEX.FILE)) + (LOAD INSPHEX.DFASL) + (ADD.PROCESS (LIST (CL:FIND-SYMBOL "HEXDUMP" "INSPHEX") + (KWOTE INSPHEX.DFASL) + '(CREATEW (CREATEREGION (FIX (TIMES 0.35 SCREENWIDTH)) + (FIX (TIMES 0.25 SCREENHEIGHT)) + (FIX (TIMES 0.5 SCREENWIDTH)) + (FIX (TIMES 0.5 SCREENHEIGHT]) +) + +(START-INSPHEX) +(DECLARE%: DONTCOPY + (FILEMAP (NIL (528 1621 (START-INSPHEX 538 . 1619))))) +STOP diff --git a/start-scripts/START-INSPHEX.LCOM b/start-scripts/START-INSPHEX.LCOM new file mode 100644 index 00000000..9ebf828e Binary files /dev/null and b/start-scripts/START-INSPHEX.LCOM differ diff --git a/start-scripts/START-INSPHEX.URL b/start-scripts/START-INSPHEX.URL new file mode 100644 index 00000000..b0e5fb6f --- /dev/null +++ b/start-scripts/START-INSPHEX.URL @@ -0,0 +1,2 @@ +https://online.interlisp.org:8081/demo?start=https%3A%2F%2Fgithub.com%2FInterlisp%2Fonline%2Fraw%2Frefs%2Fheads%2Ffgh_museum-mode%2Fstart-scripts%2FSTART-INSPHEX.LCOM + diff --git a/start-scripts/START-KINETIC b/start-scripts/START-KINETIC new file mode 100644 index 00000000..299ebbab --- /dev/null +++ b/start-scripts/START-KINETIC @@ -0,0 +1,33 @@ +(DEFINE-FILE-INFO PACKAGE "INTERLISP" READTABLE "INTERLISP" BASE 10) + +(FILECREATED " 1-Nov-2025 13:41:38" {DSK}frank>il>medley>START-KINETIC.;2 1112 + + :EDIT-BY "FGH" + + :CHANGES-TO (FNS START-KINETIC) + + :PREVIOUS-DATE " 1-Nov-2025 13:21:22" {DSK}frank>il>medley>START-KINETIC.;1) + + +(PRETTYCOMPRINT START-KINETICCOMS) + +(RPAQQ START-KINETICCOMS ((FILES KINETIC) + (FNS START-KINETIC) + (P (START-KINETIC)))) + +(FILESLOAD KINETIC) +(DEFINEQ + +(START-KINETIC + [LAMBDA NIL (* ; "Edited 1-Nov-2025 13:41 by FGH") + (* ; "Edited 1-Nov-2025 13:15 by FGH") + (ADD.PROCESS '(KINETIC (CREATEW (CREATEREGION (FIX (TIMES 0.25 SCREENWIDTH)) + (FIX (TIMES 0.25 SCREENHEIGHT)) + (FIX (TIMES 0.5 SCREENWIDTH)) + (FIX (TIMES 0.5 SCREENHEIGHT]) +) + +(START-KINETIC) +(DECLARE%: DONTCOPY + (FILEMAP (NIL (517 1068 (START-KINETIC 527 . 1066))))) +STOP diff --git a/start-scripts/START-KINETIC.URL b/start-scripts/START-KINETIC.URL new file mode 100644 index 00000000..a0816cee --- /dev/null +++ b/start-scripts/START-KINETIC.URL @@ -0,0 +1 @@ +https://online.interlisp.org:8081/demo?start=https%3A%2F%2Fgithub.com%2FInterlisp%2Fonline%2Fraw%2Frefs%2Fheads%2Ffgh_museum-mode%2Fstart-scripts%2FSTART-KINETIC diff --git a/system/install_mongodb8.0.sh b/system/install_mongodb8.0.sh new file mode 100755 index 00000000..0d72eeb0 --- /dev/null +++ b/system/install_mongodb8.0.sh @@ -0,0 +1,8 @@ +!#/bin/bash +wget -qO - https://www.mongodb.org/static/pgp/server-8.0.asc | sudo apt-key add - +echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list +sudo apt update +sudo apt install -y mongodb-org +sudo systemctl start mongod +sudo systemctl enable mongod +sudo systemctl status mongod diff --git a/web-portal/client/js/main.js b/web-portal/client/js/main.js index 7e354579..52c8c237 100644 --- a/web-portal/client/js/main.js +++ b/web-portal/client/js/main.js @@ -99,7 +99,10 @@ window.addEventListener('load', (event) => { document.getElementById("interlisp_rb").checked = true; } fillWindowOnClick(); - document.getElementById("dev-options-checkbox").checked = (localStore.getItem("show_dev_options") == "true"); + if (alStart != "") document.getElementById("start_script_url").value = alStart; + else document.getElementById("start_script_url").value = localStore.getItem("start_script_url"); + if ((localStore.getItem("show_dev_options") == "true") || (document.getElementById("start_script_url").value != "")) + document.getElementById("dev-options-checkbox").checked = true; showDevOptionsOnClick(); if( ! (isAutoLogin || fromvnc)) { if(isVerified != true) { @@ -127,7 +130,14 @@ function startSession (interlispOrXterm) { const runRooms = document.getElementById("run_rooms_cb").checked ? "true": "false"; const startSftp = document.getElementById("sftp_checkbox").checked ? "true": "false"; const medleyExec = document.getElementById("interlisp_rb").checked ? "inter" : "common"; + const startScriptUrl = + (function() { + let ss = document.getElementById("start_script_url").value; + if (ss.includes("%2F")) ss = decodeURIComponent(ss); + return ss; + })(); if(!isGuest) { + localStore.setItem("start_script_url", startScriptUrl); localStore.setItem("fill-window", fillWindow ? 'true' : 'false'); if(! fillWindow) { localStore.setItem("screen_width", screenWidth); @@ -159,36 +169,7 @@ function startSession (interlispOrXterm) { .then( data => { const isRunning = data.isRunning; const sessionType = data.target; - if(isRunning) { - new Promise((resolve, reject) => { - const dlg = document.getElementById("reconnect-dialog"); - const typeEl = document.getElementById("rd-type-span"); - typeEl.html = sessionType; - dlg.resolve = resolve; - dlg.reject = reject; - dlg.showModal(); - } - ) - .then(RorK => { - window.location.assign( - `/medley/${interlispOrXterm || "interlisp"}` - + `?screen_width=${screenWidth}` - + `&screen_height=${screenHeight}` - + `&if=${RorK}` - + `&resume=${resume || "false"}` - + `&custom=${custom || "false"}` - + `&custom_init=${customInit || "false"}` - + `¬ecards=${runNotecards || "false"}` - + `&rooms=${runRooms || "false"}` - + `&sftp=${startSftp || "false"}` - + `&exec=${medleyExec || "inter"}` - + ( isAutoLogin ? "&autologin" : "") - ); - } - ); - } - else { - window.location.assign( + const medley_url = `/medley/${interlispOrXterm || "interlisp"}` + `?screen_width=${screenWidth}` + `&screen_height=${screenHeight}` @@ -200,8 +181,22 @@ function startSession (interlispOrXterm) { + `&sftp=${startSftp || "false"}` + `&exec=${medleyExec || "inter"}` + ( isAutoLogin ? "&autologin" : "") - ); + + ( (startScriptUrl != "") ? `&start=${encodeURIComponent(startScriptUrl)}` : "" ) + ; + + if(isRunning) { + new Promise((resolve, reject) => { + const dlg = document.getElementById("reconnect-dialog"); + const typeEl = document.getElementById("rd-type-span"); + typeEl.html = sessionType; + dlg.resolve = resolve; + dlg.reject = reject; + dlg.showModal(); + } + ) + .then(RorK => { window.location.assign(medley_url + `&if=${RorK}`); } ); } + else window.location.assign(medley_url); }, reason => {} ); diff --git a/web-portal/client/views/again.pug b/web-portal/client/views/again.pug index 7bf68f8a..45545554 100644 --- a/web-portal/client/views/again.pug +++ b/web-portal/client/views/again.pug @@ -28,5 +28,5 @@ block headeradds block content .row.text-center#again-button - button.main-button(type="button" onclick='window.location.assign(decodeURI(alURL));')!= "Run Medley Again" + button.main-button(type="button" onclick='window.location.assign(decodeURIComponent(alURL));')!= "Run Medley Again" diff --git a/web-portal/client/views/help_dialogs.pug b/web-portal/client/views/help_dialogs.pug index 8267f87a..160d1840 100644 --- a/web-portal/client/views/help_dialogs.pug +++ b/web-portal/client/views/help_dialogs.pug @@ -122,3 +122,16 @@ dialog(id="help-dialog-which-exec").help-dialog Additional Exec windows based on either Interlisp or Common Lisp can be started at any time from the background menu. .single-button-div button(type="button" onclick='helpDialogClose("which-exec");').main-button OK +dialog(id="help-dialog-start-script").help-dialog + h2 Help + p. + A start-script if a Medley Lisp file that will be LOADed at the end of the ONLINE-INIT script while Online + Medley is starting up. It can be used to fetch other files from the Internet and/or to run code that will + set-up the Medley environment or start a specific Medley application. This is generally used for automatings + demos. Example start-scripts can be found at https://github.com/interlisp/online/start-scripts. + p. + In this field enter a URL that points to a Medley Lisp file that can be downloaded from the Internet with + wget. This file will be downloaded amd LOADed at the end of ONLINE-INIT. + .single-button-div + button(type="button" onclick='helpDialogClose("start-script");').main-button OK + diff --git a/web-portal/client/views/login.pug b/web-portal/client/views/login.pug index 391762dc..5dc99c51 100644 --- a/web-portal/client/views/login.pug +++ b/web-portal/client/views/login.pug @@ -41,7 +41,7 @@ block headeradds if(info) { const errorMessage = document.getElementById("error-message"); - errorMessage.innerText = info; + errorMessage.innerText = decodeURIComponent(info); //errorMessage.style.display = "block"; } else if("#{verificationNotice}" == "true") { const dlg = document.getElementById("verification-dialog"); diff --git a/web-portal/client/views/main.pug b/web-portal/client/views/main.pug index 2cb826ef..bdbe1719 100644 --- a/web-portal/client/views/main.pug +++ b/web-portal/client/views/main.pug @@ -26,6 +26,7 @@ block headeradds const alNotecards = #{notecards}; const alRooms = #{rooms}; const alURL = "#{alURL}"; + const alStart = "#{start}"; link(rel="stylesheet", href="/stylesheets/main.css") @@ -114,6 +115,19 @@ block content label.  Show advanced options #dev-div-controls(style="display:none;") + #start_script_row + div.run-option.dev-div-run-option + table(style="width:260px;") + thead + tr + th + th + tbody + tr(style="width:100%") + td(style="text-align:left;width:80%;") URL for start-script + td(style="text-align:right;width:20%;") + ? + input(type="url" id="start_script_url" name="start_script_url" class="url-input" style="width:100%;margin-bottom:12px;") #custom_sysout_row label.run-option.dev-div-run-option.  Run custom sysout diff --git a/web-portal/client/views/relogin.pug b/web-portal/client/views/relogin.pug new file mode 100644 index 00000000..1b263ccb --- /dev/null +++ b/web-portal/client/views/relogin.pug @@ -0,0 +1,50 @@ +//- + /*************************************************************************** + * + * relogin.pug: relogin page for online.interlisp.org web portal. + * + * 2025-11-09 Frank Halasz + * + * + * Copyright: 2025 by Interlisp.org + * + * + **************************************************************************/ + +extends layout + +block variables + +block headeradds + + link(rel="stylesheet", href="/stylesheets/common.css") + + script. + + window.addEventListener('load', + function() { document.getElementById("username").innerText = "#{loggedUsername}"; } + ); + + function Yes() { window.location.assign(decodeURIComponent("#{redirectYes}")); } + + function No() { window.location.assign("#{redirectNo}"); } + +block content + + div#page-title Demo Mode: Re-login? + + div.text-center.field.primary-field + p Currently logged in as: + p + p + p Keep current login? + p + p + .row + .text-center.field.primary-field#yes_no_button_div + button(type="button" id="yes_button" onclick="Yes()").main-button Yes, continue with current login + p + p + button(type="button" id="no_button" onclick="No()").main-button No, re-login + + diff --git a/web-portal/server/js/app.js b/web-portal/server/js/app.js index 469fc847..e729045f 100644 --- a/web-portal/server/js/app.js +++ b/web-portal/server/js/app.js @@ -110,26 +110,63 @@ app.get('/main', isAutoLogin: isAutoLogin, notecards: (req.query.notecards != undefined), rooms: (req.query.rooms != undefined), - alURL: alURL || "dummy" + alURL: alURL || "dummy", + start: (req.query.start != undefined) && (req.query.start != "") ? req.query.start : "" } ); } ); -app.get('/guest', - (req, res) => { - - const cookieUrl = encodeURI(`${req.protocol}://${req.get('host')}${req.originalUrl}`); - res.cookie('autologinURL', cookieUrl); - - const newQuery = {}; - newQuery.autologin = ""; - newQuery.username = config.guestUsername; - newQuery.password = config.guestPassword; - if(req.query.notecards != undefined) newQuery.notecards=""; - if(req.query.rooms != undefined) newQuery.rooms=""; - res.redirect(url.format({pathname:"/user/autologin", query: newQuery})); - } + +function autologinGoToMain(req, res, next) { + const cookieUrl = encodeURIComponent(`${req.protocol}://${req.get('host')}${req.originalUrl}`); + res.cookie('autologinURL', cookieUrl); + res.redirect(url.format({pathname:"/main", query: req.query})); +} + +function autologinReturnTo(req) { + return req.originalUrl + (req.originalUrl.includes("?") ? "&" : "?") + "autologin=true"; +} + +app.get([ '/guest', '/demo', '/demo/guest' ], + (req, res, next) => { + if(req.query.autologin === undefined) { + if (req.isAuthenticated && req.isAuthenticated()) { + req.logout(); + } + req.session.returnTo = autologinReturnTo(req); + let newQuery = {}; + newQuery.username = config.guestUsername; + newQuery.password = config.guestPassword; + res.redirect(url.format({pathname:"/user/autologin", query: newQuery})); + } + else next(); + }, + autologinGoToMain ); + +app.get([ '/demo/login' ], + (req, res, next) => { + if(req.query.autologin === undefined) { + req.session.returnTo = autologinReturnTo(req); + if (req.isAuthenticated && req.isAuthenticated()) { + if (req.user.username == config.guestUsername) { + res.redirect(url.format({ pathname:"/user/login", query:{ } })); + } + else res.render('relogin', + { + loggedUsername: req.user.username, + redirectYes: encodeURIComponent(req.session.returnTo), + redirectNo: url.format({ pathname:"/user/login", query:{ } }) + } + ); + } + else res.redirect(url.format({ pathname:"/user/login", query:{} })); + } + else next(); + }, + autologinGoToMain + ); + app.use('/user', userRouter); app.use('/medley', ensureLoggedIn(), medleyRouter); app.use('/client', ensureLoggedIn(), clientRouter); diff --git a/web-portal/server/js/medley.js b/web-portal/server/js/medley.js index bd6d7be4..9d4914a3 100644 --- a/web-portal/server/js/medley.js +++ b/web-portal/server/js/medley.js @@ -70,6 +70,13 @@ function medleyEnvs(req) { const nc = (req.query.notecards && (req.query.notecards.toLowerCase() == "true")) ? "true" : "false"; const rooms = (req.query.rooms && (req.query.rooms.toLowerCase() == "true")) ? "true" : "false"; const exec = (req.query.exec && (req.query.exec.toLowerCase() == "common")) ? "common" : "inter"; + var start = false; + var frank = 0; + try { + if ((req.query.start != undefined) && (req.query.start != "")) + start = req.query.start; + } + catch(e) { start = false; frank = 2;} return ` --env MEDLEY_EMAIL='${u.username}'` + ` --env MEDLEY_UNAME='${u.uname || "medley" }'` + ` --env MEDLEY_FIRSTNAME='${u.firstname || "Medley"}'` @@ -79,6 +86,7 @@ function medleyEnvs(req) { + ` --env RUN_ROOMS=${rooms}` + ` --env MEDLEY_EXEC=${exec}` + ` --env MEDLEY_MEMORY=${config.medleyMemoryArg}` + + ( start ? ` --env START_SCRIPT_URL="${start}"` : "" ) ; } diff --git a/web-portal/server/js/user.js b/web-portal/server/js/user.js index e09e8081..16836d5d 100644 --- a/web-portal/server/js/user.js +++ b/web-portal/server/js/user.js @@ -20,6 +20,7 @@ const {userModel, loginModel} = require('./mongodb'); const validateEmail = require('email-addresses').parseOneAddress; const crypto = require('crypto'); const gmailSend = require('./gmail-send')({user: config.gmailUsername, pass: config.gmailPassword, from: config.gmailFrom }); +const util = require('util'); // // The router @@ -101,7 +102,10 @@ function passportAuthenticate(req, res, next) { if (!user) { console.dir(info); - return res.redirect('/user/login?info=' + info); + let redirectTo = "/user/login"; + if ((info !== undefined) && (info != "")) + redirectTo = redirectTo + "?info=" + encodeURIComponent(info); + return res.redirect(redirectTo); } @@ -120,18 +124,8 @@ function passportAuthenticate(req, res, next) { } catch (err) { console.log("Error in logging login: " + err); } - if(user.uname) - if ((user.uname == "guest") && (req.query.autologin != undefined)) { - const newQuery={}; - newQuery.autologin=""; - if(req.query.notecards != undefined) newQuery.notecards=""; - if(req.query.rooms != undefined) newQuery.rooms=""; - return res.redirect(url.format({pathname:"/main", query: newQuery})); - } - else - return res.redirect('/main'); - else - return res.render('reregister', {isNCO: config.isNCO(req)}); + if(user.uname) return res.redirect(req.session.returnTo); + else return res.render('reregister', {isNCO: config.isNCO(req)}); } } ); @@ -140,7 +134,13 @@ function passportAuthenticate(req, res, next) { } userRouter.post('/login', passportAuthenticate); -userRouter.get('/autologin', passportAuthenticate); +userRouter.get('/autologin', + (req, res, next) => { + if(req.query.logout !== undefined) req.logout(); + next(); + }, + passportAuthenticate + ); userRouter.get('/login', (req, res) => {