Compare commits
6 Commits
441d17e29f
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 0459b0a84e | |||
| e77b071af1 | |||
| e6d0a8ad6a | |||
| 8c11aa6f24 | |||
| ea45c4c4f5 | |||
| 4f7be79841 |
@@ -12,7 +12,7 @@ env:
|
|||||||
GITEA_REGISTRY_USER: tesses50
|
GITEA_REGISTRY_USER: tesses50
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update-tap:
|
build-crosslang-shell-and-cpkg:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -29,9 +29,40 @@ jobs:
|
|||||||
ln -s /usr/local/bin/crosslang /usr/local/bin/crossint
|
ln -s /usr/local/bin/crosslang /usr/local/bin/crossint
|
||||||
ln -s /usr/local/bin/crosslang /usr/local/bin/crossvm
|
ln -s /usr/local/bin/crosslang /usr/local/bin/crossvm
|
||||||
crossint ./build.tcross pack
|
crossint ./build.tcross pack
|
||||||
|
crossint ./build.tcross install
|
||||||
mkdir -p artifacts
|
mkdir -p artifacts
|
||||||
cp Tesses.CrossLang.ShellPackage-*.crvm artifacts/ShellPackage.crvm
|
cp Tesses.CrossLang.ShellPackage-*.crvm artifacts/ShellPackage.crvm
|
||||||
cp Tesses.CrossLang.PackageServer/bin/Tesses.CrossLang.PackageServer-*.crvm artifacts/CPKG.crvm
|
cp Tesses.CrossLang.PackageServer/bin/Tesses.CrossLang.PackageServer-*.crvm artifacts/CPKG.crvm
|
||||||
|
cd Tesses.CrossLang.PackageServer
|
||||||
|
crosslang upload-package --token="${{ secrets.CPKG_KEY }}" --host="https://cpkg.tesseslanguage.com/"
|
||||||
|
cd ../Tesses.CrossLang.Args
|
||||||
|
crosslang upload-package --token="${{ secrets.CPKG_KEY }}" --host="https://cpkg.tesseslanguage.com/"
|
||||||
|
cd ../Tesses.CrossLang.BuildEssentials
|
||||||
|
crosslang upload-package --token="${{ secrets.CPKG_KEY }}" --host="https://cpkg.tesseslanguage.com/"
|
||||||
|
cd ../Tesses.CrossLang.Std
|
||||||
|
crosslang upload-package --token="${{ secrets.CPKG_KEY }}" --host="https://cpkg.tesseslanguage.com/"
|
||||||
|
cd ../Tesses.CrossLang.Reference
|
||||||
|
crosslang upload-package --token="${{ secrets.CPKG_KEY }}" --host="https://cpkg.tesseslanguage.com/"
|
||||||
|
cd ../Templates/compiletool
|
||||||
|
crosslang upload-package --token="${{ secrets.CPKG_KEY }}" --host="https://cpkg.tesseslanguage.com/"
|
||||||
|
cd ../console
|
||||||
|
crosslang upload-package --token="${{ secrets.CPKG_KEY }}" --host="https://cpkg.tesseslanguage.com/"
|
||||||
|
cd ../emptyweb
|
||||||
|
crosslang upload-package --token="${{ secrets.CPKG_KEY }}" --host="https://cpkg.tesseslanguage.com/"
|
||||||
|
cd ../lib
|
||||||
|
crosslang upload-package --token="${{ secrets.CPKG_KEY }}" --host="https://cpkg.tesseslanguage.com/"
|
||||||
|
cd ../template
|
||||||
|
crosslang upload-package --token="${{ secrets.CPKG_KEY }}" --host="https://cpkg.tesseslanguage.com/"
|
||||||
|
cd ../tool
|
||||||
|
crosslang upload-package --token="${{ secrets.CPKG_KEY }}" --host="https://cpkg.tesseslanguage.com/"
|
||||||
|
cd ../web
|
||||||
|
crosslang upload-package --token="${{ secrets.CPKG_KEY }}" --host="https://cpkg.tesseslanguage.com/"
|
||||||
|
cd ../webapp
|
||||||
|
crosslang upload-package --token="${{ secrets.CPKG_KEY }}" --host="https://cpkg.tesseslanguage.com/"
|
||||||
|
cd ../npmweb
|
||||||
|
crosslang upload-package --token="${{ secrets.CPKG_KEY }}" --host="https://cpkg.tesseslanguage.com/"
|
||||||
|
cd ../npmwebapp
|
||||||
|
crosslang upload-package --token="${{ secrets.CPKG_KEY }}" --host="https://cpkg.tesseslanguage.com/"
|
||||||
- name: "Publish artifacts"
|
- name: "Publish artifacts"
|
||||||
uses: akkuman/gitea-release-action@v1
|
uses: akkuman/gitea-release-action@v1
|
||||||
env:
|
env:
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -8,3 +8,7 @@ tmp
|
|||||||
vscode-extension/out
|
vscode-extension/out
|
||||||
vscode-extension/package-lock.json
|
vscode-extension/package-lock.json
|
||||||
vscode-extension/node-modules
|
vscode-extension/node-modules
|
||||||
|
Packages
|
||||||
|
Tesses.CrossLang.PackageServer/conf.json
|
||||||
|
Tesses.CrossLang.PackageServer/data.db
|
||||||
|
Temp
|
||||||
10
Changelog.md
Normal file
10
Changelog.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
## Changelog
|
||||||
|
|
||||||
|
## v0.0.2
|
||||||
|
Add the templates for npm
|
||||||
|
|
||||||
|
## v0.0.1
|
||||||
|
Make CPKG more complete
|
||||||
|
|
||||||
|
## v0.0.0
|
||||||
|
Migrate to Gitea
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
FROM git.tesses.org/tesses50/crosslang:latest
|
FROM git.tesses.org/tesses50/crosslang:latest
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY ./Tesses.CrossLang.PackageServer/bin/Tesses.CrossLang.PackageServer-1.0.0.0-prod.crvm /app/Tesses.CrossLang.PackageServer-1.0.0.0-prod.crvm
|
COPY ./Tesses.CrossLang.PackageServer/bin/Tesses.CrossLang.PackageServer-1.0.0.0-dev.crvm /app/Tesses.CrossLang.PackageServer-1.0.0.0-dev.crvm
|
||||||
|
|
||||||
EXPOSE 4206
|
EXPOSE 4206
|
||||||
ENTRYPOINT ["crossvm","Tesses.CrossLang.PackageServer-1.0.0.0-prod.crvm","/data"]
|
ENTRYPOINT ["crossvm","Tesses.CrossLang.PackageServer-1.0.0.0-dev.crvm","/data"]
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
# CrossLang Essentials
|
# CrossLang Essentials
|
||||||
|
|
||||||
> :warning: **NOT READY FOR PRODUCTION**
|
> :warning: **NOT READY FOR PRODUCTION, BECAUSE IT MAY (WILL) HAVE BREAKING CHANGES**
|
||||||
|
|
||||||
[CrossLang](https://gitea.site.tesses.net/tesses50/crosslang) is required to build this
|
[CrossLang](https://git.tesses.org/tesses50/crosslang) is required to build this
|
||||||
|
|
||||||
# To Build
|
# To Build
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -1,3 +1,2 @@
|
|||||||
bin
|
bin
|
||||||
obj
|
obj
|
||||||
.DS_Store
|
|
||||||
5
Templates/compiletool/.gitignore
vendored
Normal file
5
Templates/compiletool/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.DS_Store
|
||||||
|
bin
|
||||||
|
obj
|
||||||
|
publish
|
||||||
|
thumbs.db
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "Tesses.CrossLang.Template.CompileTool",
|
"name": "Tesses.CrossLang.Template.CompileTool",
|
||||||
"version": "1.0.0.0-prod",
|
"version": "1.0.0.0-dev",
|
||||||
"info": {
|
"info": {
|
||||||
"maintainer": "Mike Nolan",
|
"maintainer": "Mike Nolan",
|
||||||
"type": "template",
|
"type": "template",
|
||||||
"repo": "https://onedev.site.tesses.net/CrossLang/CrossLangExtras",
|
"repo": "https://git.tesses.org/tesses50/crosslangextras",
|
||||||
"homepage": "https://crosslang.tesseslanguage.com/",
|
"homepage": "https://crosslang.tesseslanguage.com/",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"short_name": "compiletool",
|
"short_name": "compiletool",
|
||||||
|
|||||||
@@ -1,3 +1,2 @@
|
|||||||
bin
|
bin
|
||||||
obj
|
obj
|
||||||
.DS_Store
|
|
||||||
5
Templates/console/.gitignore
vendored
Normal file
5
Templates/console/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.DS_Store
|
||||||
|
bin
|
||||||
|
obj
|
||||||
|
publish
|
||||||
|
thumbs.db
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "Tesses.CrossLang.Template.Console",
|
"name": "Tesses.CrossLang.Template.Console",
|
||||||
"version": "1.0.0.0-prod",
|
"version": "1.0.0.0-dev",
|
||||||
"info": {
|
"info": {
|
||||||
"maintainer": "Mike Nolan",
|
"maintainer": "Mike Nolan",
|
||||||
"type": "template",
|
"type": "template",
|
||||||
"repo": "https://onedev.site.tesses.net/CrossLang/CrossLangExtras",
|
"repo": "https://git.tesses.org/tesses50/crosslangextras",
|
||||||
"homepage": "https://crosslang.tesseslanguage.com/",
|
"homepage": "https://crosslang.tesseslanguage.com/",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"short_name": "console",
|
"short_name": "console",
|
||||||
|
|||||||
@@ -1,3 +1,2 @@
|
|||||||
bin
|
bin
|
||||||
obj
|
obj
|
||||||
.DS_Store
|
|
||||||
5
Templates/emptyweb/.gitignore
vendored
Normal file
5
Templates/emptyweb/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.DS_Store
|
||||||
|
bin
|
||||||
|
obj
|
||||||
|
publish
|
||||||
|
thumbs.db
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "Tesses.CrossLang.Template.EmptyWebsite",
|
"name": "Tesses.CrossLang.Template.EmptyWebsite",
|
||||||
"version": "1.0.0.0-prod",
|
"version": "1.0.0.0-dev",
|
||||||
"info": {
|
"info": {
|
||||||
"maintainer": "Mike Nolan",
|
"maintainer": "Mike Nolan",
|
||||||
"type": "template",
|
"type": "template",
|
||||||
"repo": "https://onedev.site.tesses.net/CrossLang/CrossLangExtras",
|
"repo": "https://git.tesses.org/tesses50/crosslangextras",
|
||||||
"homepage": "https://crosslang.tesseslanguage.com/",
|
"homepage": "https://crosslang.tesseslanguage.com/",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"short_name": "emptyweb",
|
"short_name": "emptyweb",
|
||||||
|
|||||||
@@ -1,3 +1,2 @@
|
|||||||
bin
|
bin
|
||||||
obj
|
obj
|
||||||
.DS_Store
|
|
||||||
5
Templates/lib/.gitignore
vendored
Normal file
5
Templates/lib/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.DS_Store
|
||||||
|
bin
|
||||||
|
obj
|
||||||
|
publish
|
||||||
|
thumbs.db
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "Tesses.CrossLang.Template.Library",
|
"name": "Tesses.CrossLang.Template.Library",
|
||||||
"version": "1.0.0.0-prod",
|
"version": "1.0.0.0-dev",
|
||||||
"info": {
|
"info": {
|
||||||
"maintainer": "Mike Nolan",
|
"maintainer": "Mike Nolan",
|
||||||
"type": "template",
|
"type": "template",
|
||||||
"repo": "https://onedev.site.tesses.net/CrossLang/CrossLangExtras",
|
"repo": "https://git.tesses.org/tesses50/crosslangextras",
|
||||||
"homepage": "https://crosslang.tesseslanguage.com/",
|
"homepage": "https://crosslang.tesseslanguage.com/",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"short_name": "lib",
|
"short_name": "lib",
|
||||||
|
|||||||
8
Templates/npmweb/.crossarchiveignore
Normal file
8
Templates/npmweb/.crossarchiveignore
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
.DS_Store
|
||||||
|
bin
|
||||||
|
obj
|
||||||
|
publish
|
||||||
|
npm/node_modules
|
||||||
|
npm/package-lock.json
|
||||||
|
npm/dist
|
||||||
|
thumbs.db
|
||||||
8
Templates/npmweb/.gitignore
vendored
Normal file
8
Templates/npmweb/.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
.DS_Store
|
||||||
|
bin
|
||||||
|
obj
|
||||||
|
publish
|
||||||
|
npm/node_modules
|
||||||
|
npm/package-lock.json
|
||||||
|
npm/dist
|
||||||
|
thumbs.db
|
||||||
41
Templates/npmweb/cross.json
Normal file
41
Templates/npmweb/cross.json
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https:\/\/crosslang.tesseslanguage.com\/\/schema\/cross-json-schema.json",
|
||||||
|
"info": {
|
||||||
|
"template_ignored_files": [
|
||||||
|
".DS_Store",
|
||||||
|
"bin",
|
||||||
|
"obj",
|
||||||
|
"publish",
|
||||||
|
"npm/node_modules",
|
||||||
|
"npm/package-lock.json",
|
||||||
|
"npm/dist",
|
||||||
|
"thumbs.db"
|
||||||
|
],
|
||||||
|
"short_name_pretty": "NPM WebSite",
|
||||||
|
"maintainer": "Mike Nolan",
|
||||||
|
"type": "template",
|
||||||
|
"repo": "https://git.tesses.org/tesses50/crosslangextras",
|
||||||
|
"homepage": "https://crosslang.tesseslanguage.com/",
|
||||||
|
"license": "MIT",
|
||||||
|
"short_name": "npmweb",
|
||||||
|
"description": "A NPM Website Template with BeerCSS and HTMX",
|
||||||
|
"template_info": {
|
||||||
|
"type": "console"
|
||||||
|
},
|
||||||
|
"template_prebuild": [
|
||||||
|
{
|
||||||
|
"workdir": "npm",
|
||||||
|
"commands": [
|
||||||
|
["npm","install"],
|
||||||
|
["npm","run","publish"]
|
||||||
|
],
|
||||||
|
"res": [
|
||||||
|
"npm/dist"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": "Tesses.CrossLang.Template.NPMWebsite",
|
||||||
|
"version": "1.0.0.0-dev"
|
||||||
|
|
||||||
|
}
|
||||||
12
Templates/npmweb/npm/package.json
Normal file
12
Templates/npmweb/npm/package.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"beercss": "^4.0.21",
|
||||||
|
"htmx.org": "^2.0.10"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"esbuild": "^0.28.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"publish": "esbuild --minify --sourcemap --define:'process.env.NODE_ENV=\"production\"' --bundle --outdir=dist web.mjs --loader:.svg=file --loader:.woff2=file"
|
||||||
|
}
|
||||||
|
}
|
||||||
78
Templates/npmweb/npm/web.css
Normal file
78
Templates/npmweb/npm/web.css
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
:root,
|
||||||
|
body.light {
|
||||||
|
--primary:#855400;
|
||||||
|
--on-primary:#ffffff;
|
||||||
|
--primary-container:#ffddb7;
|
||||||
|
--on-primary-container:#2a1700;
|
||||||
|
--secondary:#705b41;
|
||||||
|
--on-secondary:#ffffff;
|
||||||
|
--secondary-container:#fcdebc;
|
||||||
|
--on-secondary-container:#281805;
|
||||||
|
--tertiary:#53643e;
|
||||||
|
--on-tertiary:#ffffff;
|
||||||
|
--tertiary-container:#d6e9b9;
|
||||||
|
--on-tertiary-container:#121f03;
|
||||||
|
--error:#ba1a1a;
|
||||||
|
--on-error:#ffffff;
|
||||||
|
--error-container:#ffdad6;
|
||||||
|
--on-error-container:#410002;
|
||||||
|
--background:#fffbff;
|
||||||
|
--on-background:#1f1b16;
|
||||||
|
--surface:#fff8f4;
|
||||||
|
--on-surface:#1f1b16;
|
||||||
|
--surface-variant:#f0e0d0;
|
||||||
|
--on-surface-variant:#504539;
|
||||||
|
--outline:#827568;
|
||||||
|
--outline-variant:#d4c4b5;
|
||||||
|
--shadow:#000000;
|
||||||
|
--scrim:#000000;
|
||||||
|
--inverse-surface:#352f2a;
|
||||||
|
--inverse-on-surface:#f9efe7;
|
||||||
|
--inverse-primary:#ffb95c;
|
||||||
|
--surface-dim:#e2d8d1;
|
||||||
|
--surface-bright:#fff8f4;
|
||||||
|
--surface-container-lowest:#ffffff;
|
||||||
|
--surface-container-low:#fcf2ea;
|
||||||
|
--surface-container:#f6ece4;
|
||||||
|
--surface-container-high:#f0e6de;
|
||||||
|
--surface-container-highest:#ebe1d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark {
|
||||||
|
--primary:#ffb95c;
|
||||||
|
--on-primary:#462a00;
|
||||||
|
--primary-container:#653e00;
|
||||||
|
--on-primary-container:#ffddb7;
|
||||||
|
--secondary:#dfc2a2;
|
||||||
|
--on-secondary:#3f2d17;
|
||||||
|
--secondary-container:#57432b;
|
||||||
|
--on-secondary-container:#fcdebc;
|
||||||
|
--tertiary:#bacd9f;
|
||||||
|
--on-tertiary:#263514;
|
||||||
|
--tertiary-container:#3c4c28;
|
||||||
|
--on-tertiary-container:#d6e9b9;
|
||||||
|
--error:#ffb4ab;
|
||||||
|
--on-error:#690005;
|
||||||
|
--error-container:#93000a;
|
||||||
|
--on-error-container:#ffb4ab;
|
||||||
|
--background:#1f1b16;
|
||||||
|
--on-background:#ebe1d9;
|
||||||
|
--surface:#17130e;
|
||||||
|
--on-surface:#ebe1d9;
|
||||||
|
--surface-variant:#504539;
|
||||||
|
--on-surface-variant:#d4c4b5;
|
||||||
|
--outline:#9c8e80;
|
||||||
|
--outline-variant:#504539;
|
||||||
|
--shadow:#000000;
|
||||||
|
--scrim:#000000;
|
||||||
|
--inverse-surface:#ebe1d9;
|
||||||
|
--inverse-on-surface:#352f2a;
|
||||||
|
--inverse-primary:#855400;
|
||||||
|
--surface-dim:#17130e;
|
||||||
|
--surface-bright:#3e3833;
|
||||||
|
--surface-container-lowest:#110e09;
|
||||||
|
--surface-container-low:#1f1b16;
|
||||||
|
--surface-container:#231f1a;
|
||||||
|
--surface-container-high:#2e2924;
|
||||||
|
--surface-container-highest:#39342f;
|
||||||
|
}
|
||||||
3
Templates/npmweb/npm/web.mjs
Normal file
3
Templates/npmweb/npm/web.mjs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import 'beercss'
|
||||||
|
import 'htmx.org'
|
||||||
|
import './web.css'
|
||||||
78
Templates/npmweb/src/components/shell.tcross
Normal file
78
Templates/npmweb/src/components/shell.tcross
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
func Components.Shell(title,pages,body)
|
||||||
|
{
|
||||||
|
<return>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="stylesheet" href="/dist/web.css">
|
||||||
|
<title>%PROJECT_NAME% - {title}</title>
|
||||||
|
<script src="/dist/web.js" defer></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<dialog class="left" id="leftpane">
|
||||||
|
<header>
|
||||||
|
<nav>
|
||||||
|
<img class="circle large" src="/tytd-128.png">
|
||||||
|
<h6 class="max">%PROJECT_NAME%</h6>
|
||||||
|
<button hx-on:click="ui('#leftpane')" class="transparent circle large">
|
||||||
|
<i>close</i>
|
||||||
|
</button>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
<div class="space"></div>
|
||||||
|
<ul class="list">
|
||||||
|
<each(var item : pages)>
|
||||||
|
<if(item.active)>
|
||||||
|
<true>
|
||||||
|
<li class="wave round primary" hx-target="body" hx-push-url="true" hx-get={item.link}>
|
||||||
|
<i>{item.icon}</i>
|
||||||
|
<span class="max">{item.text}</span>
|
||||||
|
<b></b>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
</true>
|
||||||
|
<false>
|
||||||
|
<li class="wave round" hx-target="body" hx-push-url="true" hx-get={item.route}>
|
||||||
|
<i>{item.icon}</i>
|
||||||
|
<span class="max">{item.text}</span>
|
||||||
|
<b></b>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
</false>
|
||||||
|
</if>
|
||||||
|
</each>
|
||||||
|
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</dialog>
|
||||||
|
<header class="fixed primary-container">
|
||||||
|
<nav>
|
||||||
|
<button hx-on:click="ui('#leftpane')" class="circle transparent">
|
||||||
|
<i>menu</i>
|
||||||
|
</button>
|
||||||
|
<button hx-target="body" hx-push-url="true" hx-get="/" class="circle transparent">
|
||||||
|
<i>home</i>
|
||||||
|
</button>
|
||||||
|
<div class="max"></div>
|
||||||
|
<div>
|
||||||
|
<button class="circle transparent">
|
||||||
|
<i>more_vert</i>
|
||||||
|
</button>
|
||||||
|
<menu class="left no-wrap">
|
||||||
|
<li><a href="https://beercss.com/">BeerCSS</a></li>
|
||||||
|
</menu>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<div class="small-padding">
|
||||||
|
<h5>%PROJECT_NAME%</h5>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main class="responsive">
|
||||||
|
<raw(body)>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
</return>
|
||||||
|
}
|
||||||
33
Templates/npmweb/src/pages/about.tcross
Normal file
33
Templates/npmweb/src/pages/about.tcross
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
|
||||||
|
func Pages.About(ctx)
|
||||||
|
{
|
||||||
|
var pages = [
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/",
|
||||||
|
text = "Home",
|
||||||
|
icon = "home"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/counter",
|
||||||
|
text = "Counter",
|
||||||
|
icon = "exposure_plus_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active = true,
|
||||||
|
route = "/about",
|
||||||
|
text = "About",
|
||||||
|
icon = "info"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
ctx.WithMimeType("text/html").SendText(Components.Shell("About Me",pages,<section>
|
||||||
|
<h1>About Me</h1>
|
||||||
|
<p>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
30
Templates/npmweb/src/pages/counter.tcross
Normal file
30
Templates/npmweb/src/pages/counter.tcross
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
var counter = 0;
|
||||||
|
|
||||||
|
func Pages.Counter(ctx)
|
||||||
|
{
|
||||||
|
var pages = [
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/",
|
||||||
|
text = "Home",
|
||||||
|
icon = "home"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active = true,
|
||||||
|
route = "/counter",
|
||||||
|
text = "Counter",
|
||||||
|
icon = "exposure_plus_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/about",
|
||||||
|
text = "About",
|
||||||
|
icon = "info"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
ctx.WithMimeType("text/html").SendText(Components.Shell("Counter",pages,<section>
|
||||||
|
<button hx-get="./counter" hx-target="body" hx-push-url="true">Counter is {++counter}</button>
|
||||||
|
</section>
|
||||||
|
));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
35
Templates/npmweb/src/pages/echo.tcross
Normal file
35
Templates/npmweb/src/pages/echo.tcross
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
func Pages.Echo(ctx)
|
||||||
|
{
|
||||||
|
const text = ctx.QueryParams.TryGetFirst("text");
|
||||||
|
var pages = [
|
||||||
|
{
|
||||||
|
active = true,
|
||||||
|
route = "/",
|
||||||
|
text = "Home",
|
||||||
|
icon = "home"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/counter",
|
||||||
|
text = "Counter",
|
||||||
|
icon = "exposure_plus_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/about",
|
||||||
|
text = "About",
|
||||||
|
icon = "info"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
ctx.WithMimeType("text/html").SendText(Components.Shell("Echo",pages,<section>
|
||||||
|
<if(text != null)>
|
||||||
|
<true>
|
||||||
|
<plink(text)>
|
||||||
|
</true>
|
||||||
|
<false>
|
||||||
|
<p>No text available</p>
|
||||||
|
</false>
|
||||||
|
</if>
|
||||||
|
</section>));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
42
Templates/npmweb/src/pages/index.tcross
Normal file
42
Templates/npmweb/src/pages/index.tcross
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
func Pages.Index(ctx)
|
||||||
|
{
|
||||||
|
var pages = [
|
||||||
|
{
|
||||||
|
active = true,
|
||||||
|
route = "/",
|
||||||
|
text = "Home",
|
||||||
|
icon = "home"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/counter",
|
||||||
|
text = "Counter",
|
||||||
|
icon = "exposure_plus_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/about",
|
||||||
|
text = "About",
|
||||||
|
icon = "info"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
ctx.WithMimeType("text/html").SendText(Components.Shell("Main Page",pages,<section>
|
||||||
|
<form hx-get="./echo" hx-target="body" hx-push-url="true" action="./echo" method="GET">
|
||||||
|
<div class="row">
|
||||||
|
<div class="max">
|
||||||
|
<div class="field label border">
|
||||||
|
<input type="text" name="text">
|
||||||
|
<label>Text to echo</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="min">
|
||||||
|
<button type="submit">
|
||||||
|
Echo
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<p>1 John 4:4: You, dear children, are from God and have overcome them, because the one who is in you is greater than the one who is in the world.</p>
|
||||||
|
</section>));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
40
Templates/npmweb/src/program.tcross
Normal file
40
Templates/npmweb/src/program.tcross
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
class MyWebApp {
|
||||||
|
private fileServer;
|
||||||
|
private mountable;
|
||||||
|
private pages;
|
||||||
|
|
||||||
|
public MyWebApp()
|
||||||
|
{
|
||||||
|
this.fileServer = new FileServer(embeddir("/"), true, false);
|
||||||
|
|
||||||
|
this.mountable = new MountableServer((ctx)=>{
|
||||||
|
const page = this.pages.[ctx.Path];
|
||||||
|
if(TypeIsDefined(page)) return page(ctx);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
this.mountable.Mount("/dist/",this.fileServer);
|
||||||
|
this.pages = {
|
||||||
|
.["/"] = Pages.Index,
|
||||||
|
.["/counter"] = Pages.Counter,
|
||||||
|
.["/about"] = Pages.About,
|
||||||
|
.["/echo"] = Pages.Echo
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Handle(ctx)
|
||||||
|
{
|
||||||
|
return this.mountable.Handle(ctx);
|
||||||
|
}
|
||||||
|
public Close()
|
||||||
|
{
|
||||||
|
this.mountable = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main(args)
|
||||||
|
{
|
||||||
|
const webApp=new MyWebApp();
|
||||||
|
Net.Http.ListenSimpleWithLoop(webApp,4206);
|
||||||
|
|
||||||
|
webApp.Close();
|
||||||
|
}
|
||||||
8
Templates/npmwebapp/.crossarchiveignore
Normal file
8
Templates/npmwebapp/.crossarchiveignore
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
.DS_Store
|
||||||
|
bin
|
||||||
|
obj
|
||||||
|
publish
|
||||||
|
npm/node_modules
|
||||||
|
npm/package-lock.json
|
||||||
|
npm/dist
|
||||||
|
thumbs.db
|
||||||
8
Templates/npmwebapp/.gitignore
vendored
Normal file
8
Templates/npmwebapp/.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
.DS_Store
|
||||||
|
bin
|
||||||
|
obj
|
||||||
|
publish
|
||||||
|
npm/node_modules
|
||||||
|
npm/package-lock.json
|
||||||
|
npm/dist
|
||||||
|
thumbs.db
|
||||||
43
Templates/npmwebapp/cross.json
Normal file
43
Templates/npmwebapp/cross.json
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https:\/\/crosslang.tesseslanguage.com\/\/schema\/cross-json-schema.json",
|
||||||
|
"info": {
|
||||||
|
"template_ignored_files": [
|
||||||
|
".DS_Store",
|
||||||
|
"bin",
|
||||||
|
"obj",
|
||||||
|
"publish",
|
||||||
|
"npm/node_modules",
|
||||||
|
"npm/package-lock.json",
|
||||||
|
"npm/dist",
|
||||||
|
"thumbs.db"
|
||||||
|
],
|
||||||
|
"short_name_pretty": "NPM WebApp",
|
||||||
|
"maintainer": "Mike Nolan",
|
||||||
|
"type": "template",
|
||||||
|
"repo": "https://git.tesses.org/tesses50/crosslangextras",
|
||||||
|
"homepage": "https://crosslang.tesseslanguage.com/",
|
||||||
|
"license": "MIT",
|
||||||
|
"short_name": "npmwebapp",
|
||||||
|
"description": "A NPM WebApp Template with BeerCSS and HTMX",
|
||||||
|
"template_info": {
|
||||||
|
"type": "webapp",
|
||||||
|
"short_name": "changeme",
|
||||||
|
"short_name_pretty": "Change Me"
|
||||||
|
},
|
||||||
|
"template_prebuild": [
|
||||||
|
{
|
||||||
|
"workdir": "npm",
|
||||||
|
"commands": [
|
||||||
|
["npm","install"],
|
||||||
|
["npm","run","publish"]
|
||||||
|
],
|
||||||
|
"res": [
|
||||||
|
"npm/dist"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": "Tesses.CrossLang.Template.NPMWebApp",
|
||||||
|
"version": "1.0.0.0-dev"
|
||||||
|
|
||||||
|
}
|
||||||
12
Templates/npmwebapp/npm/package.json
Normal file
12
Templates/npmwebapp/npm/package.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"beercss": "^4.0.21",
|
||||||
|
"htmx.org": "^2.0.10"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"esbuild": "^0.28.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"publish": "esbuild --minify --sourcemap --define:'process.env.NODE_ENV=\"production\"' --bundle --outdir=dist web.mjs --loader:.svg=file --loader:.woff2=file"
|
||||||
|
}
|
||||||
|
}
|
||||||
78
Templates/npmwebapp/npm/web.css
Normal file
78
Templates/npmwebapp/npm/web.css
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
:root,
|
||||||
|
body.light {
|
||||||
|
--primary:#855400;
|
||||||
|
--on-primary:#ffffff;
|
||||||
|
--primary-container:#ffddb7;
|
||||||
|
--on-primary-container:#2a1700;
|
||||||
|
--secondary:#705b41;
|
||||||
|
--on-secondary:#ffffff;
|
||||||
|
--secondary-container:#fcdebc;
|
||||||
|
--on-secondary-container:#281805;
|
||||||
|
--tertiary:#53643e;
|
||||||
|
--on-tertiary:#ffffff;
|
||||||
|
--tertiary-container:#d6e9b9;
|
||||||
|
--on-tertiary-container:#121f03;
|
||||||
|
--error:#ba1a1a;
|
||||||
|
--on-error:#ffffff;
|
||||||
|
--error-container:#ffdad6;
|
||||||
|
--on-error-container:#410002;
|
||||||
|
--background:#fffbff;
|
||||||
|
--on-background:#1f1b16;
|
||||||
|
--surface:#fff8f4;
|
||||||
|
--on-surface:#1f1b16;
|
||||||
|
--surface-variant:#f0e0d0;
|
||||||
|
--on-surface-variant:#504539;
|
||||||
|
--outline:#827568;
|
||||||
|
--outline-variant:#d4c4b5;
|
||||||
|
--shadow:#000000;
|
||||||
|
--scrim:#000000;
|
||||||
|
--inverse-surface:#352f2a;
|
||||||
|
--inverse-on-surface:#f9efe7;
|
||||||
|
--inverse-primary:#ffb95c;
|
||||||
|
--surface-dim:#e2d8d1;
|
||||||
|
--surface-bright:#fff8f4;
|
||||||
|
--surface-container-lowest:#ffffff;
|
||||||
|
--surface-container-low:#fcf2ea;
|
||||||
|
--surface-container:#f6ece4;
|
||||||
|
--surface-container-high:#f0e6de;
|
||||||
|
--surface-container-highest:#ebe1d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark {
|
||||||
|
--primary:#ffb95c;
|
||||||
|
--on-primary:#462a00;
|
||||||
|
--primary-container:#653e00;
|
||||||
|
--on-primary-container:#ffddb7;
|
||||||
|
--secondary:#dfc2a2;
|
||||||
|
--on-secondary:#3f2d17;
|
||||||
|
--secondary-container:#57432b;
|
||||||
|
--on-secondary-container:#fcdebc;
|
||||||
|
--tertiary:#bacd9f;
|
||||||
|
--on-tertiary:#263514;
|
||||||
|
--tertiary-container:#3c4c28;
|
||||||
|
--on-tertiary-container:#d6e9b9;
|
||||||
|
--error:#ffb4ab;
|
||||||
|
--on-error:#690005;
|
||||||
|
--error-container:#93000a;
|
||||||
|
--on-error-container:#ffb4ab;
|
||||||
|
--background:#1f1b16;
|
||||||
|
--on-background:#ebe1d9;
|
||||||
|
--surface:#17130e;
|
||||||
|
--on-surface:#ebe1d9;
|
||||||
|
--surface-variant:#504539;
|
||||||
|
--on-surface-variant:#d4c4b5;
|
||||||
|
--outline:#9c8e80;
|
||||||
|
--outline-variant:#504539;
|
||||||
|
--shadow:#000000;
|
||||||
|
--scrim:#000000;
|
||||||
|
--inverse-surface:#ebe1d9;
|
||||||
|
--inverse-on-surface:#352f2a;
|
||||||
|
--inverse-primary:#855400;
|
||||||
|
--surface-dim:#17130e;
|
||||||
|
--surface-bright:#3e3833;
|
||||||
|
--surface-container-lowest:#110e09;
|
||||||
|
--surface-container-low:#1f1b16;
|
||||||
|
--surface-container:#231f1a;
|
||||||
|
--surface-container-high:#2e2924;
|
||||||
|
--surface-container-highest:#39342f;
|
||||||
|
}
|
||||||
3
Templates/npmwebapp/npm/web.mjs
Normal file
3
Templates/npmwebapp/npm/web.mjs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import 'beercss'
|
||||||
|
import 'htmx.org'
|
||||||
|
import './web.css'
|
||||||
78
Templates/npmwebapp/src/components/shell.tcross
Normal file
78
Templates/npmwebapp/src/components/shell.tcross
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
func Components.Shell(title,pages,body)
|
||||||
|
{
|
||||||
|
<return>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="stylesheet" href="/dist/web.css">
|
||||||
|
<title>%PROJECT_NAME% - {title}</title>
|
||||||
|
<script src="/dist/web.js" defer></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<dialog class="left" id="leftpane">
|
||||||
|
<header>
|
||||||
|
<nav>
|
||||||
|
<img class="circle large" src="/tytd-128.png">
|
||||||
|
<h6 class="max">%PROJECT_NAME%</h6>
|
||||||
|
<button hx-on:click="ui('#leftpane')" class="transparent circle large">
|
||||||
|
<i>close</i>
|
||||||
|
</button>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
<div class="space"></div>
|
||||||
|
<ul class="list">
|
||||||
|
<each(var item : pages)>
|
||||||
|
<if(item.active)>
|
||||||
|
<true>
|
||||||
|
<li class="wave round primary" hx-target="body" hx-push-url="true" hx-get={item.link}>
|
||||||
|
<i>{item.icon}</i>
|
||||||
|
<span class="max">{item.text}</span>
|
||||||
|
<b></b>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
</true>
|
||||||
|
<false>
|
||||||
|
<li class="wave round" hx-target="body" hx-push-url="true" hx-get={item.route}>
|
||||||
|
<i>{item.icon}</i>
|
||||||
|
<span class="max">{item.text}</span>
|
||||||
|
<b></b>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
</false>
|
||||||
|
</if>
|
||||||
|
</each>
|
||||||
|
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</dialog>
|
||||||
|
<header class="fixed primary-container">
|
||||||
|
<nav>
|
||||||
|
<button hx-on:click="ui('#leftpane')" class="circle transparent">
|
||||||
|
<i>menu</i>
|
||||||
|
</button>
|
||||||
|
<button hx-target="body" hx-push-url="true" hx-get="/" class="circle transparent">
|
||||||
|
<i>home</i>
|
||||||
|
</button>
|
||||||
|
<div class="max"></div>
|
||||||
|
<div>
|
||||||
|
<button class="circle transparent">
|
||||||
|
<i>more_vert</i>
|
||||||
|
</button>
|
||||||
|
<menu class="left no-wrap">
|
||||||
|
<li><a href="https://beercss.com/">BeerCSS</a></li>
|
||||||
|
</menu>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<div class="small-padding">
|
||||||
|
<h5>%PROJECT_NAME%</h5>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main class="responsive">
|
||||||
|
<raw(body)>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
</return>
|
||||||
|
}
|
||||||
33
Templates/npmwebapp/src/pages/about.tcross
Normal file
33
Templates/npmwebapp/src/pages/about.tcross
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
|
||||||
|
func Pages.About(ctx)
|
||||||
|
{
|
||||||
|
var pages = [
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/",
|
||||||
|
text = "Home",
|
||||||
|
icon = "home"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/counter",
|
||||||
|
text = "Counter",
|
||||||
|
icon = "exposure_plus_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active = true,
|
||||||
|
route = "/about",
|
||||||
|
text = "About",
|
||||||
|
icon = "info"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
ctx.WithMimeType("text/html").SendText(Components.Shell("About Me",pages,<section>
|
||||||
|
<h1>About Me</h1>
|
||||||
|
<p>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
30
Templates/npmwebapp/src/pages/counter.tcross
Normal file
30
Templates/npmwebapp/src/pages/counter.tcross
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
var counter = 0;
|
||||||
|
|
||||||
|
func Pages.Counter(ctx)
|
||||||
|
{
|
||||||
|
var pages = [
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/",
|
||||||
|
text = "Home",
|
||||||
|
icon = "home"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active = true,
|
||||||
|
route = "/counter",
|
||||||
|
text = "Counter",
|
||||||
|
icon = "exposure_plus_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/about",
|
||||||
|
text = "About",
|
||||||
|
icon = "info"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
ctx.WithMimeType("text/html").SendText(Components.Shell("Counter",pages,<section>
|
||||||
|
<button hx-get="./counter" hx-target="body" hx-push-url="true">Counter is {++counter}</button>
|
||||||
|
</section>
|
||||||
|
));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
35
Templates/npmwebapp/src/pages/echo.tcross
Normal file
35
Templates/npmwebapp/src/pages/echo.tcross
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
func Pages.Echo(ctx)
|
||||||
|
{
|
||||||
|
const text = ctx.QueryParams.TryGetFirst("text");
|
||||||
|
var pages = [
|
||||||
|
{
|
||||||
|
active = true,
|
||||||
|
route = "/",
|
||||||
|
text = "Home",
|
||||||
|
icon = "home"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/counter",
|
||||||
|
text = "Counter",
|
||||||
|
icon = "exposure_plus_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/about",
|
||||||
|
text = "About",
|
||||||
|
icon = "info"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
ctx.WithMimeType("text/html").SendText(Components.Shell("Echo",pages,<section>
|
||||||
|
<if(text != null)>
|
||||||
|
<true>
|
||||||
|
<plink(text)>
|
||||||
|
</true>
|
||||||
|
<false>
|
||||||
|
<p>No text available</p>
|
||||||
|
</false>
|
||||||
|
</if>
|
||||||
|
</section>));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
42
Templates/npmwebapp/src/pages/index.tcross
Normal file
42
Templates/npmwebapp/src/pages/index.tcross
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
func Pages.Index(ctx)
|
||||||
|
{
|
||||||
|
var pages = [
|
||||||
|
{
|
||||||
|
active = true,
|
||||||
|
route = "/",
|
||||||
|
text = "Home",
|
||||||
|
icon = "home"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/counter",
|
||||||
|
text = "Counter",
|
||||||
|
icon = "exposure_plus_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/about",
|
||||||
|
text = "About",
|
||||||
|
icon = "info"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
ctx.WithMimeType("text/html").SendText(Components.Shell("Main Page",pages,<section>
|
||||||
|
<form hx-get="./echo" hx-target="body" hx-push-url="true" action="./echo" method="GET">
|
||||||
|
<div class="row">
|
||||||
|
<div class="max">
|
||||||
|
<div class="field label border">
|
||||||
|
<input type="text" name="text">
|
||||||
|
<label>Text to echo</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="min">
|
||||||
|
<button type="submit">
|
||||||
|
Echo
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<p>1 John 4:4: You, dear children, are from God and have overcome them, because the one who is in you is greater than the one who is in the world.</p>
|
||||||
|
</section>));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
37
Templates/npmwebapp/src/program.tcross
Normal file
37
Templates/npmwebapp/src/program.tcross
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
class MyWebApp {
|
||||||
|
private fileServer;
|
||||||
|
private mountable;
|
||||||
|
private pages;
|
||||||
|
|
||||||
|
public MyWebApp()
|
||||||
|
{
|
||||||
|
this.fileServer = new FileServer(embeddir("/"), true, false);
|
||||||
|
|
||||||
|
this.mountable = new MountableServer((ctx)=>{
|
||||||
|
const page = this.pages.[ctx.Path];
|
||||||
|
if(TypeIsDefined(page)) return page(ctx);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
this.mountable.Mount("/dist/",this.fileServer);
|
||||||
|
this.pages = {
|
||||||
|
.["/"] = Pages.Index,
|
||||||
|
.["/counter"] = Pages.Counter,
|
||||||
|
.["/about"] = Pages.About,
|
||||||
|
.["/echo"] = Pages.Echo
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Handle(ctx)
|
||||||
|
{
|
||||||
|
return this.mountable.Handle(ctx);
|
||||||
|
}
|
||||||
|
public Close()
|
||||||
|
{
|
||||||
|
this.mountable = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WebAppMain(args)
|
||||||
|
{
|
||||||
|
return new MyWebApp();
|
||||||
|
}
|
||||||
5
Templates/template/.gitignore
vendored
Normal file
5
Templates/template/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.DS_Store
|
||||||
|
bin
|
||||||
|
obj
|
||||||
|
publish
|
||||||
|
thumbs.db
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "Tesses.CrossLang.Template.Template",
|
"name": "Tesses.CrossLang.Template.Template",
|
||||||
"version": "1.0.0.0-prod",
|
"version": "1.0.0.0-dev",
|
||||||
"info": {
|
"info": {
|
||||||
"maintainer": "Mike Nolan",
|
"maintainer": "Mike Nolan",
|
||||||
"type": "template",
|
"type": "template",
|
||||||
"repo": "https://onedev.site.tesses.net/CrossLang/CrossLangExtras",
|
"repo": "https://git.tesses.org/tesses50/crosslangextras",
|
||||||
"homepage": "https://crosslang.tesseslanguage.com/",
|
"homepage": "https://crosslang.tesseslanguage.com/",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"short_name": "template",
|
"short_name": "template",
|
||||||
|
|||||||
5
Templates/tool/.gitignore
vendored
Normal file
5
Templates/tool/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.DS_Store
|
||||||
|
bin
|
||||||
|
obj
|
||||||
|
publish
|
||||||
|
thumbs.db
|
||||||
@@ -17,12 +17,12 @@
|
|||||||
"description": "A crosslang tool that you can run via crosslang tool",
|
"description": "A crosslang tool that you can run via crosslang tool",
|
||||||
"type": "template",
|
"type": "template",
|
||||||
"maintainer": "Mike Nolan",
|
"maintainer": "Mike Nolan",
|
||||||
"repo": "https://onedev.site.tesses.net/CrossLang/CrossLangExtras",
|
"repo": "https://git.tesses.org/tesses50/crosslangextras",
|
||||||
"homepage": "https://crosslang.tesseslanguage.com/",
|
"homepage": "https://crosslang.tesseslanguage.com/",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"short_name_pretty": "Tool"
|
"short_name_pretty": "Tool"
|
||||||
},
|
},
|
||||||
"version": "1.0.0.0-prod",
|
"version": "1.0.0.0-dev",
|
||||||
"name": "Tesses.CrossLang.Template.Tool",
|
"name": "Tesses.CrossLang.Template.Tool",
|
||||||
"$schema": "https://crosslang.tesseslanguage.com//schema/cross-json-schema.json"
|
"$schema": "https://crosslang.tesseslanguage.com//schema/cross-json-schema.json"
|
||||||
}
|
}
|
||||||
5
Templates/web/.gitignore
vendored
Normal file
5
Templates/web/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.DS_Store
|
||||||
|
bin
|
||||||
|
obj
|
||||||
|
publish
|
||||||
|
thumbs.db
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "Tesses.CrossLang.Template.Website",
|
"name": "Tesses.CrossLang.Template.Website",
|
||||||
"version": "1.0.0.0-prod",
|
"version": "1.0.0.0-dev",
|
||||||
"info": {
|
"info": {
|
||||||
"maintainer": "Mike Nolan",
|
"maintainer": "Mike Nolan",
|
||||||
"type": "template",
|
"type": "template",
|
||||||
"repo": "https://onedev.site.tesses.net/CrossLang/CrossLangExtras",
|
"repo": "https://git.tesses.org/tesses50/crosslangextras",
|
||||||
"homepage": "https://crosslang.tesseslanguage.com/",
|
"homepage": "https://crosslang.tesseslanguage.com/",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"short_name": "web",
|
"short_name": "web",
|
||||||
|
|||||||
5
Templates/webapp/.gitignore
vendored
Normal file
5
Templates/webapp/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.DS_Store
|
||||||
|
bin
|
||||||
|
obj
|
||||||
|
publish
|
||||||
|
thumbs.db
|
||||||
@@ -15,12 +15,12 @@
|
|||||||
"short_name_pretty": "Web Application",
|
"short_name_pretty": "Web Application",
|
||||||
"template_project_dependencies": [
|
"template_project_dependencies": [
|
||||||
],
|
],
|
||||||
"repo": "https://onedev.site.tesses.net/CrossLang/CrossLangExtras",
|
"repo": "https://git.tesses.org/tesses50/crosslangextras",
|
||||||
"homepage": "https://crosslang.tesseslanguage.com/",
|
"homepage": "https://crosslang.tesseslanguage.com/",
|
||||||
"type": "template",
|
"type": "template",
|
||||||
"description": "A web app (for webview or eventual cloud OS)"
|
"description": "A web app (for webview or eventual cloud OS)"
|
||||||
},
|
},
|
||||||
"name": "Tesses.CrossLang.Template.WebApp",
|
"name": "Tesses.CrossLang.Template.WebApp",
|
||||||
"version": "1.0.0.0-prod",
|
"version": "1.0.0.0-dev",
|
||||||
"$schema": "https://crosslang.tesseslanguage.com//schema/cross-json-schema.json"
|
"$schema": "https://crosslang.tesseslanguage.com//schema/cross-json-schema.json"
|
||||||
}
|
}
|
||||||
@@ -11,5 +11,5 @@
|
|||||||
"project_dependencies": [
|
"project_dependencies": [
|
||||||
"..\/Tesses.CrossLang.BuildEssentials"
|
"..\/Tesses.CrossLang.BuildEssentials"
|
||||||
],
|
],
|
||||||
"version": "1.0.0.0-prod"
|
"version": "1.0.0.0-dev"
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "Tesses.CrossLang.Args",
|
"name": "Tesses.CrossLang.Args",
|
||||||
"version": "1.0.0.0-prod",
|
"version": "1.0.0.0-dev",
|
||||||
"info": {
|
"info": {
|
||||||
"maintainer": "Mike Nolan",
|
"maintainer": "Mike Nolan",
|
||||||
"type": "lib",
|
"type": "lib",
|
||||||
"repo": "https://onedev.site.tesses.net/CrossLang/CrossLangExtras",
|
"repo": "https://git.tesses.org/tesses50/crosslangextras",
|
||||||
"homepage": "https://crosslang.tesseslanguage.com/",
|
"homepage": "https://crosslang.tesseslanguage.com/",
|
||||||
"license": "LGPLv3"
|
"license": "LGPLv3"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "Tesses.CrossLang.BuildEssentials",
|
"name": "Tesses.CrossLang.BuildEssentials",
|
||||||
"version": "1.0.0.0-prod",
|
"version": "1.0.0.0-dev",
|
||||||
"info": {
|
"info": {
|
||||||
"maintainer": "Mike Nolan",
|
"maintainer": "Mike Nolan",
|
||||||
"type": "lib",
|
"type": "lib",
|
||||||
"repo": "https://onedev.site.tesses.net/CrossLang/CrossLangExtras",
|
"repo": "https://git.tesses.org/tesses50/crosslangextras",
|
||||||
"homepage": "https://crosslang.tesseslanguage.com/",
|
"homepage": "https://crosslang.tesseslanguage.com/",
|
||||||
"license": "LGPLv3"
|
"license": "LGPLv3"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,13 @@
|
|||||||
"info": {
|
"info": {
|
||||||
"type": "console",
|
"type": "console",
|
||||||
"short_name": "packageserver",
|
"short_name": "packageserver",
|
||||||
"short_name_pretty": "Package Server"
|
"short_name_pretty": "Package Server",
|
||||||
|
"description": "This webapp allows you to serve packages",
|
||||||
|
"repo": "https://git.tesses.org/tesses50/crosslangextras",
|
||||||
|
"homepage": "https://cpkg.tesseslanguage.com/",
|
||||||
|
"license": "AGPLv3"
|
||||||
},
|
},
|
||||||
"version": "1.0.0.0-prod",
|
"version": "1.0.0.0-dev",
|
||||||
"name": "Tesses.CrossLang.PackageServer",
|
"name": "Tesses.CrossLang.PackageServer",
|
||||||
"compTime": "secure"
|
"compTime": "secure"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ func DB.CreateUserFromAdmin(email, name, password, flags)
|
|||||||
var res = {Success=true};
|
var res = {Success=true};
|
||||||
DB.Lock();
|
DB.Lock();
|
||||||
var dbCon = DB.Open();
|
var dbCon = DB.Open();
|
||||||
exec = Sqlite.Exec(dbCon,$"SELECT * FROM accounts WHERE accountName = {Sqlite.Escape(name)};");
|
var exec = Sqlite.Exec(dbCon,$"SELECT * FROM accounts WHERE accountName = {Sqlite.Escape(name)};");
|
||||||
|
|
||||||
if(TypeOf(exec) == "List" && exec.Length > 0)
|
if(TypeOf(exec) == "List" && exec.Length > 0)
|
||||||
{
|
{
|
||||||
res = {Success=false, Reason = "Name already exists"};
|
res = {Success=false, Reason = "Name already exists"};
|
||||||
@@ -75,8 +76,8 @@ func DB.CreateUserFromAdmin(email, name, password, flags)
|
|||||||
{
|
{
|
||||||
var salt = Crypto.RandomBytes(32, "CPKG");
|
var salt = Crypto.RandomBytes(32, "CPKG");
|
||||||
var hash = Crypto.PBKDF2(password, salt, DB.ITTR,64,384);
|
var hash = Crypto.PBKDF2(password, salt, DB.ITTR,64,384);
|
||||||
|
const now = DateTime.NowEpoch ?? 0;
|
||||||
var r = Sqlite.Exec(dbCon,$"INSERT INTO accounts (email, accountName, password_hash, password_salt, verifyExpire, flags) values ({Sqlite.Escape(email)},{Sqlite.Escape(name)},{Sqlite.Escape(Crypto.Base64Encode(hash))},{Sqlite.Escape(Crypto.Base64Encode(salt))},{0},{flags});");
|
var r = Sqlite.Exec(dbCon,$"INSERT INTO accounts (email, accountName, password_hash, password_salt, verifyExpire, flags, created, verified) values ({Sqlite.Escape(email)},{Sqlite.Escape(name)},{Sqlite.Escape(Crypto.Base64Encode(hash))},{Sqlite.Escape(Crypto.Base64Encode(salt))},{0},{flags},{now},{now});");
|
||||||
if(TypeOf(r) == "String") res = {Success = false, Reason = r};
|
if(TypeOf(r) == "String") res = {Success = false, Reason = r};
|
||||||
res = {Success=true};
|
res = {Success=true};
|
||||||
}
|
}
|
||||||
@@ -87,8 +88,12 @@ func DB.CreateUserFromAdmin(email, name, password, flags)
|
|||||||
|
|
||||||
var verify_hash = Crypto.RandomBytes(32, "CPKG");
|
var verify_hash = Crypto.RandomBytes(32, "CPKG");
|
||||||
var verify_hash_str = Crypto.Base64Encode(verify_hash);
|
var verify_hash_str = Crypto.Base64Encode(verify_hash);
|
||||||
|
const now = DateTime.NowEpoch ?? 0;
|
||||||
|
|
||||||
var r = Sqlite.Exec(dbCon,$"INSERT INTO accounts (email, accountName, password_hash, password_salt, verifyKey, verifyExpire, flags) values ({Sqlite.Escape(email)},{Sqlite.Escape(name)},{Sqlite.Escape(Crypto.Base64Encode(hash))},{Sqlite.Escape(Crypto.Base64Encode(salt))},{Sqlite.Escape(verify_hash_str)},{DateTime.NowEpoch+600},{flags});");
|
const resp = $"INSERT INTO accounts (email, accountName, password_hash, password_salt, verifyKey, verifyExpire, flags, created, verified) values ({Sqlite.Escape(email)},{Sqlite.Escape(name)},{Sqlite.Escape(Crypto.Base64Encode(hash))},{Sqlite.Escape(Crypto.Base64Encode(salt))},{Sqlite.Escape(verify_hash_str)},{now+600},{flags},{now},0);";
|
||||||
|
Console.WriteLine(resp);
|
||||||
|
var r = Sqlite.Exec(dbCon, resp);
|
||||||
|
Console.WriteLine(r);
|
||||||
if(TypeOf(r) == "String") res = {Success = false, Reason = r};
|
if(TypeOf(r) == "String") res = {Success = false, Reason = r};
|
||||||
|
|
||||||
if(DB.Config.MailConfig)
|
if(DB.Config.MailConfig)
|
||||||
@@ -111,8 +116,8 @@ func DB.CreateUser(email, name, password)
|
|||||||
|
|
||||||
var salt = Crypto.RandomBytes(32, "CPKG");
|
var salt = Crypto.RandomBytes(32, "CPKG");
|
||||||
var hash = Crypto.PBKDF2(password, salt, DB.ITTR,64,384);
|
var hash = Crypto.PBKDF2(password, salt, DB.ITTR,64,384);
|
||||||
|
const now = DateTime.NowEpoch ?? 0;
|
||||||
var r = Sqlite.Exec(dbCon,$"INSERT INTO accounts (email, accountName, password_hash, password_salt, flags) values ({Sqlite.Escape(email)},{Sqlite.Escape(name)},{Sqlite.Escape(Crypto.Base64Encode(hash))},{Sqlite.Escape(Crypto.Base64Encode(salt))},{DB.FLAG_ADMIN|DB.FLAG_VERIFIED});");
|
var r = Sqlite.Exec(dbCon,$"INSERT INTO accounts (email, accountName, password_hash, password_salt, flags, created, verified) values ({Sqlite.Escape(email)},{Sqlite.Escape(name)},{Sqlite.Escape(Crypto.Base64Encode(hash))},{Sqlite.Escape(Crypto.Base64Encode(salt))},{DB.FLAG_ADMIN|DB.FLAG_VERIFIED},{now},{now});");
|
||||||
if(TypeOf(r) == "String") res = {Success = false, Reason = r};
|
if(TypeOf(r) == "String") res = {Success = false, Reason = r};
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -146,8 +151,8 @@ func DB.CreateUser(email, name, password)
|
|||||||
|
|
||||||
var verify_hash = Crypto.RandomBytes(32, "CPKG");
|
var verify_hash = Crypto.RandomBytes(32, "CPKG");
|
||||||
var verify_hash_str = Crypto.Base64Encode(verify_hash);
|
var verify_hash_str = Crypto.Base64Encode(verify_hash);
|
||||||
|
const now = DateTime.NowEpoch ?? 0;
|
||||||
var r = Sqlite.Exec(dbCon,$"INSERT INTO accounts (email, accountName, password_hash, password_salt, verifyKey, verifyExpire, flags) values ({Sqlite.Escape(email)},{Sqlite.Escape(name)},{Sqlite.Escape(Crypto.Base64Encode(hash))},{Sqlite.Escape(Crypto.Base64Encode(salt))},{Sqlite.Escape(verify_hash_str)},{DateTime.NowEpoch+600},{DB.FLAG_VERIFY});");
|
var r = Sqlite.Exec(dbCon,$"INSERT INTO accounts (email, accountName, password_hash, password_salt, verifyKey, verifyExpire, flags, created, verified) values ({Sqlite.Escape(email)},{Sqlite.Escape(name)},{Sqlite.Escape(Crypto.Base64Encode(hash))},{Sqlite.Escape(Crypto.Base64Encode(salt))},{Sqlite.Escape(verify_hash_str)},{now+600},{DB.FLAG_VERIFY},{now},0);");
|
||||||
if(TypeOf(r) == "String") {res = {Success = false, Reason = r};}
|
if(TypeOf(r) == "String") {res = {Success = false, Reason = r};}
|
||||||
else {
|
else {
|
||||||
if(DB.Config.MailConfig)
|
if(DB.Config.MailConfig)
|
||||||
|
|||||||
@@ -105,8 +105,8 @@ func DB.Init(working)
|
|||||||
var dbCon = DB.Open();
|
var dbCon = DB.Open();
|
||||||
Sqlite.Exec(dbCon,"CREATE TABLE IF NOT EXISTS packages (id INTEGER PRIMARY KEY AUTOINCREMENT, packageName TEXT UNIQUE, accountId INTEGER);");
|
Sqlite.Exec(dbCon,"CREATE TABLE IF NOT EXISTS packages (id INTEGER PRIMARY KEY AUTOINCREMENT, packageName TEXT UNIQUE, accountId INTEGER);");
|
||||||
Sqlite.Exec(dbCon,"CREATE TABLE IF NOT EXISTS versions (id INTEGER PRIMARY KEY AUTOINCREMENT, packageId INTEGER, version INTEGER, description TEXT, type TEXT, maintainer TEXT, homepage TEXT, repo TEXT, license TEXT, uploadTime INTEGER, pluginHost TEXT);");
|
Sqlite.Exec(dbCon,"CREATE TABLE IF NOT EXISTS versions (id INTEGER PRIMARY KEY AUTOINCREMENT, packageId INTEGER, version INTEGER, description TEXT, type TEXT, maintainer TEXT, homepage TEXT, repo TEXT, license TEXT, uploadTime INTEGER, pluginHost TEXT);");
|
||||||
Sqlite.Exec(dbCon,"CREATE TABLE IF NOT EXISTS accounts (id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT UNIQUE, accountName TEXT UNIQUE, password_hash TEXT, password_salt TEXT, motto TEXT, verifyKey TEXT UNIQUE, verifyExpire INTEGER, flags INTEGER);");
|
Sqlite.Exec(dbCon,"CREATE TABLE IF NOT EXISTS accounts (id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT UNIQUE, accountName TEXT UNIQUE, password_hash TEXT, password_salt TEXT, motto TEXT, verifyKey TEXT UNIQUE, verifyExpire INTEGER, flags INTEGER, created INTEGER, verified INTEGER);");
|
||||||
Sqlite.Exec(dbCon,"CREATE TABLE IF NOT EXISTS sessions (id INTEGER PRIMARY KEY AUTOINCREMENT, accountId INTEGER, key STRING UNIQUE);");
|
Sqlite.Exec(dbCon,"CREATE TABLE IF NOT EXISTS sessions (id INTEGER PRIMARY KEY AUTOINCREMENT, accountId INTEGER, key STRING UNIQUE, expires INTEGER, created INTEGER, name TEXT);");
|
||||||
Sqlite.Exec(dbCon,"CREATE TABLE IF NOT EXISTS reserved_prefixes (id INTEGER PRIMARY KEY AUTOINCREMENT, accountId INTEGER, prefix STRING UNIQUE);");
|
Sqlite.Exec(dbCon,"CREATE TABLE IF NOT EXISTS reserved_prefixes (id INTEGER PRIMARY KEY AUTOINCREMENT, accountId INTEGER, prefix STRING UNIQUE);");
|
||||||
Sqlite.Close(dbCon);
|
Sqlite.Close(dbCon);
|
||||||
}
|
}
|
||||||
@@ -119,5 +119,6 @@ DB.FLAG_VERIFY = 0b00000100;
|
|||||||
|
|
||||||
DB.ITTR = 35000;
|
DB.ITTR = 35000;
|
||||||
|
|
||||||
|
DB.Expires = 86400*7;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -151,7 +151,8 @@ func DB.VerifyEmail(verifyKey)
|
|||||||
{
|
{
|
||||||
flags &= ~DB.FLAG_VERIFY;
|
flags &= ~DB.FLAG_VERIFY;
|
||||||
flags |= DB.FLAG_VERIFIED;
|
flags |= DB.FLAG_VERIFIED;
|
||||||
Sqlite.Exec(dbCon,$"UPDATE accounts SET flags = {flags} WHERE id = {exec[0].id};");
|
const now = DateTime.NowEpoch;
|
||||||
|
Sqlite.Exec(dbCon,$"UPDATE accounts SET flags = {flags} WHERE id = {exec[0].id}, verified = {now};");
|
||||||
Sqlite.Close(dbCon);
|
Sqlite.Close(dbCon);
|
||||||
DB.Unlock();
|
DB.Unlock();
|
||||||
return { Success=true };
|
return { Success=true };
|
||||||
|
|||||||
@@ -458,3 +458,43 @@ func DB.QueryReservedPrefixes(name)
|
|||||||
Items = items
|
Items = items
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DB.DownloadPackage(log,userId,server, name, version)
|
||||||
|
{
|
||||||
|
Console.WriteLine("INDLPKG");
|
||||||
|
if(!DB.CanUploadPackagePrefix(userId,name)) return;
|
||||||
|
|
||||||
|
var res = DB.PackageExists(userId, {Name = name, Version = Version.Parse(version)});
|
||||||
|
if(res == 2 || res == 4) return;
|
||||||
|
|
||||||
|
const resp=Net.Http.MakeRequest($"{server.TrimEnd('/')}/api/v1/download?name={Net.Http.UrlEncode(name)}&version={Net.Http.UrlEncode(version)}",{FollowRedirects=true});
|
||||||
|
if(resp.StatusCode >= 200 && resp.StatusCode <= 299)
|
||||||
|
{
|
||||||
|
var filePath = DB.working / "Temp" / $"{DB.GetUniqueNumber()}.crvm";
|
||||||
|
|
||||||
|
var strm = FS.Local.OpenFile(filePath,"wb");
|
||||||
|
resp.CopyToStream(strm);
|
||||||
|
strm.Close();
|
||||||
|
resp.Close();
|
||||||
|
|
||||||
|
//we need to load the exec, because the main thing erases it
|
||||||
|
strm = FS.Local.OpenFile(filePath,"rb");
|
||||||
|
const exec = VM.LoadExecutable(strm);
|
||||||
|
strm.Close();
|
||||||
|
const status = DB.UploadPackage(userId, filePath);
|
||||||
|
if(status.Success)
|
||||||
|
{
|
||||||
|
each(var item in exec.Dependencies)
|
||||||
|
{
|
||||||
|
DB.DownloadPackage(log, userId, server, item.Name, item.Version.ToString());
|
||||||
|
}
|
||||||
|
each(var item in exec.Tools)
|
||||||
|
{
|
||||||
|
DB.DownloadPackage(log, userId, server, item.Name, item.Version.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log($"Failed to add package: {name} with {version}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,12 +4,37 @@ func DB.GetUserIdFromSession(session)
|
|||||||
var dbCon = DB.Open();
|
var dbCon = DB.Open();
|
||||||
var exec = Sqlite.Exec(dbCon,$"SELECT * FROM sessions WHERE key = {Sqlite.Escape(session)};");
|
var exec = Sqlite.Exec(dbCon,$"SELECT * FROM sessions WHERE key = {Sqlite.Escape(session)};");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(TypeOf(exec) == "List" && exec.Length == 1)
|
||||||
|
{
|
||||||
|
var expiry = 0;
|
||||||
|
const expires = ParseLong(exec[0].expires);
|
||||||
|
if(TypeIsLong(expires) && expires != 0)
|
||||||
|
{
|
||||||
|
const whenItExpires = ParseLong(expires);
|
||||||
|
const currentTime = DateTime.NowEpoch ?? 0;
|
||||||
|
if(whenItExpires != 0 && currentTime < whenItExpires && (whenItExpires - currentTime) < (DB.Expires-3600))
|
||||||
|
{
|
||||||
|
expiry = currentTime + DB.Expires;
|
||||||
|
Sqlite.Exec(dbCon, $"UPDATE sessions SET expires = {expiry} WHERE key = {Sqlite.Escape(session)};");
|
||||||
|
}
|
||||||
|
else if(whenItExpires != 0 && currentTime >= whenItExpires)
|
||||||
|
{
|
||||||
|
Sqlite.Exec(dbCon, $"DELETE FROM sessions WHERE key = {Sqlite.Escape(session)};");
|
||||||
|
Sqlite.Close(dbCon);
|
||||||
|
DB.Unlock();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
Sqlite.Close(dbCon);
|
||||||
|
DB.Unlock();
|
||||||
|
return { accountId = ParseLong(exec[0].accountId), expiry };
|
||||||
|
}
|
||||||
Sqlite.Close(dbCon);
|
Sqlite.Close(dbCon);
|
||||||
DB.Unlock();
|
DB.Unlock();
|
||||||
|
return null;
|
||||||
if(TypeOf(exec) == "List" && exec.Length == 1) return ParseLong(exec[0].accountId);
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
func DB.GetSessionFromBearer(ctx)
|
func DB.GetSessionFromBearer(ctx)
|
||||||
{
|
{
|
||||||
@@ -20,7 +45,7 @@ func DB.GetSessionFromBearer(ctx)
|
|||||||
if(auth.Length < 2) return null;
|
if(auth.Length < 2) return null;
|
||||||
if(auth[0] != "Bearer") return null;
|
if(auth[0] != "Bearer") return null;
|
||||||
var uid = DB.GetUserIdFromSession(auth[1]);
|
var uid = DB.GetUserIdFromSession(auth[1]);
|
||||||
if(uid != -1) return auth[1];
|
if(TypeIsDictionary(uid)) return auth[1];
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -37,23 +62,34 @@ func DB.GetSession(ctx)
|
|||||||
if(cookieKV.Length == 2 && cookieKV[0] == "Session")
|
if(cookieKV.Length == 2 && cookieKV[0] == "Session")
|
||||||
{
|
{
|
||||||
var session = cookieKV[1];
|
var session = cookieKV[1];
|
||||||
var sessionId = DB.GetUserIdFromSession(session);
|
var sessionObj = DB.GetUserIdFromSession(session);
|
||||||
|
|
||||||
|
if(TypeIsDictionary(sessionObj))
|
||||||
|
{
|
||||||
|
if(sessionObj.expiry > 0)
|
||||||
|
{
|
||||||
|
ctx.WithHeader("Set-Cookie",$"Session={session}; SameSite=Lax; Expires={new DateTime(sessionObj.expiry).ToHttpDate()}");
|
||||||
|
}
|
||||||
|
|
||||||
if(sessionId != -1)
|
|
||||||
return session;
|
return session;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
func DB.CreateSession(userId)
|
func DB.CreateSession(userId, doesExpire, name)
|
||||||
{
|
{
|
||||||
|
const now = DateTime.NowEpoch;
|
||||||
|
const expiryTime = doesExpire ? (DB.Expires + now) : 0;
|
||||||
|
|
||||||
|
|
||||||
DB.Lock();
|
DB.Lock();
|
||||||
var dbCon = DB.Open();
|
var dbCon = DB.Open();
|
||||||
|
|
||||||
var rand = Net.Http.UrlEncode(Crypto.Base64Encode(Crypto.RandomBytes(32, "CPKG")));
|
var rand = Net.Http.UrlEncode(Crypto.Base64Encode(Crypto.RandomBytes(32, "CPKG")));
|
||||||
Sqlite.Exec(dbCon, $"INSERT INTO sessions (accountId,key) VALUES ({userId},{Sqlite.Escape(rand)});");
|
Sqlite.Exec(dbCon,$"INSERT INTO sessions (accountId,key, expires, created, name) VALUES ({userId},{Sqlite.Escape(rand)},{Sqlite.Escape(expiryTime)},{Sqlite.Escape(now)}, {Sqlite.Escape(name)});");
|
||||||
Sqlite.Close(dbCon);
|
Sqlite.Close(dbCon);
|
||||||
DB.Unlock();
|
DB.Unlock();
|
||||||
return rand;
|
return rand;
|
||||||
|
|||||||
@@ -81,8 +81,18 @@ func Pages.Account(ctx)
|
|||||||
<if(TypeOf(user) == "Dictionary")>
|
<if(TypeOf(user) == "Dictionary")>
|
||||||
<true>
|
<true>
|
||||||
<h1>{user.accountName}</h1>
|
<h1>{user.accountName}</h1>
|
||||||
<a href={$"./packages?account={Net.Http.UrlEncode(name)}"}>Packages</a>|<a href={$"./reserved_prefixes?name={Net.Http.UrlEncode(name)}"}>Reserved Prefixes</a>
|
<h6>Created: {new DateTime(ParseLong(user.created)).ToString("%Y/%m/%d %H:%M:%S UTC")}</h6>
|
||||||
|
<if(user.verified != "0")>
|
||||||
|
<true>
|
||||||
|
<h6>Verified: {new DateTime(ParseLong(user.verified)).ToString("%Y/%m/%d %H:%M:%S UTC")}</h6>
|
||||||
|
</true>
|
||||||
|
<false>
|
||||||
|
<h6>Not verified</h6>
|
||||||
|
</false>
|
||||||
|
</if>
|
||||||
|
<div>
|
||||||
|
<a href={$"./packages?account={Net.Http.UrlEncode(name)}"}>Packages</a> | <a href={$"./reserved_prefixes?name={Net.Http.UrlEncode(name)}"}>Reserved Prefixes</a>
|
||||||
|
</div>
|
||||||
<if(active.active)>
|
<if(active.active)>
|
||||||
<true>
|
<true>
|
||||||
|
|
||||||
@@ -100,6 +110,7 @@ func Pages.Account(ctx)
|
|||||||
<a class="btn btn-secondary" href="./admin">Admin</a>
|
<a class="btn btn-secondary" href="./admin">Admin</a>
|
||||||
</true>
|
</true>
|
||||||
</if>
|
</if>
|
||||||
|
<a class="btn btn-info" href="./sessions">Sessions</a>
|
||||||
<a class="btn btn-danger" href="./delete_packages">Delete Packages</a>
|
<a class="btn btn-danger" href="./delete_packages">Delete Packages</a>
|
||||||
<a class="btn btn-danger" href="./logout">Logout</a>
|
<a class="btn btn-danger" href="./logout">Logout</a>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -33,6 +33,95 @@ func Pages.Admin(ctx)
|
|||||||
//we have authorization
|
//we have authorization
|
||||||
switch(action2)
|
switch(action2)
|
||||||
{
|
{
|
||||||
|
case "cache_package":
|
||||||
|
{
|
||||||
|
const userInfo = DB.GetUserIdFromSession(active.session);
|
||||||
|
const url = ctx.QueryParams.TryGetFirst("url");
|
||||||
|
|
||||||
|
if(!TypeIsString(url) || url.Length == 0 || !url.Contains("/package?name=") || !TypeIsDictionary(userInfo))
|
||||||
|
{
|
||||||
|
ctx.StatusCode = 400;
|
||||||
|
return Shell("Invalid input", pages,<h1>Invalid Input</h1>);
|
||||||
|
}
|
||||||
|
|
||||||
|
const components=url.Split("/package?name=");
|
||||||
|
if(components.Length < 2)
|
||||||
|
{
|
||||||
|
ctx.StatusCode = 400;
|
||||||
|
return Shell("Invalid input", pages,<h1>Invalid Input</h1>);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const strm = ctx.WithMimeType("text/html").OpenResponseStream();
|
||||||
|
const textWriter = new StreamWriter(strm);
|
||||||
|
textWriter.Write("<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><meta name=\"color-scheme\" content=\"dark light\"></head><body>");
|
||||||
|
|
||||||
|
var finished = false;
|
||||||
|
var errors = "";
|
||||||
|
|
||||||
|
const thread = new Thread(()=>{
|
||||||
|
|
||||||
|
func log(err)
|
||||||
|
{
|
||||||
|
errors += "{err}\n";
|
||||||
|
}
|
||||||
|
const server = components[0];
|
||||||
|
const name = Net.Http.UrlDecode(components[1]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const resp=Net.Http.MakeRequest($"{server.TrimEnd('/')}/api/v1/versions?name={Net.Http.UrlEncode(name)}",{FollowRedirects=true});
|
||||||
|
|
||||||
|
if(resp.StatusCode >= 200 && resp.StatusCode <= 299)
|
||||||
|
{
|
||||||
|
const respJson = resp.ReadAsJson();
|
||||||
|
resp.Close();
|
||||||
|
if(respJson.success)
|
||||||
|
{
|
||||||
|
if(TypeIsList(respJson.versions))
|
||||||
|
{
|
||||||
|
each(var item in respJson.versions)
|
||||||
|
{
|
||||||
|
if(TypeIsString(item.version))
|
||||||
|
{
|
||||||
|
DB.DownloadPackage(log,userInfo.accountId,server, name, item.version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log("versions is not list");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log("versions json does not indicate success");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log($"Status code does not indicate success {resp.StatusCode} {Net.Http.StatusCodeString(resp.StatusCode)}");
|
||||||
|
}
|
||||||
|
} catch(ex) {
|
||||||
|
log(ex.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
finished=true;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
while(!finished)
|
||||||
|
{
|
||||||
|
textWriter.Write(".");
|
||||||
|
DateTime.Sleep(1000);
|
||||||
|
}
|
||||||
|
errors = Net.Http.HtmlEncode(errors).Replace("\n","<br>");
|
||||||
|
textWriter.Write($"{}<br>Done <a href=\"./admin\">Go Back</a></body></html>");
|
||||||
|
|
||||||
|
thread.Join();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
case "server_config":
|
case "server_config":
|
||||||
{
|
{
|
||||||
var prefix = ctx.QueryParams.TryGetFirst("prefix");
|
var prefix = ctx.QueryParams.TryGetFirst("prefix");
|
||||||
@@ -129,7 +218,7 @@ func Pages.Admin(ctx)
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset class="border p-2">
|
<fieldset class="border p-2">
|
||||||
<legend class="float-none w-auto">Accounts</legend>
|
<legend class="float-none w-auto">Accounts</legend>
|
||||||
<form action="./admin_account" method="get">
|
<form action="./admin_accounts" method="get">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="account" class="form-label">Account Name</label>
|
<label for="account" class="form-label">Account Name</label>
|
||||||
<input class="form-control" name="account" id="account" type="text" placeholder="Account Name" aria-label="Account Name">
|
<input class="form-control" name="account" id="account" type="text" placeholder="Account Name" aria-label="Account Name">
|
||||||
|
|||||||
305
Tesses.CrossLang.PackageServer/src/pages/admin_account.tcross
Normal file
305
Tesses.CrossLang.PackageServer/src/pages/admin_account.tcross
Normal file
@@ -0,0 +1,305 @@
|
|||||||
|
func Pages.AdminAccount(ctx)
|
||||||
|
{
|
||||||
|
var active = DB.LoginButton(ctx,false,"");
|
||||||
|
var csrf="";
|
||||||
|
|
||||||
|
|
||||||
|
var pages = [
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/packages",
|
||||||
|
text = "Packages"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/upload",
|
||||||
|
text = "Upload"
|
||||||
|
},
|
||||||
|
active
|
||||||
|
];
|
||||||
|
if(!active.admin) ctx.StatusCode = 401;
|
||||||
|
|
||||||
|
|
||||||
|
if(ctx.Method == "POST")
|
||||||
|
{
|
||||||
|
var csrf2 = ctx.QueryParams.TryGetFirst("csrf");
|
||||||
|
if(!active.admin) {ctx.StatusCode = 401; return Shell("Not an admin", pages,<h1>Not an admin</h1>);}
|
||||||
|
if(TypeOf(csrf2) != "String") {ctx.StatusCode = 401; return Shell("Invalid CSRF", pages,<h1>Invalid CSRF</h1>);}
|
||||||
|
if(DB.VerifyCSRF(active.session, csrf2))
|
||||||
|
{
|
||||||
|
|
||||||
|
const oldname = ctx.QueryParams.TryGetFirst("oldname");
|
||||||
|
const newname = ctx.QueryParams.TryGetFirst("newname");
|
||||||
|
const motto = ctx.QueryParams.TryGetFirst("motto") ?? "";
|
||||||
|
const admin = ctx.QueryParams.GetFirstBoolean("admin");
|
||||||
|
const verified = ctx.QueryParams.GetFirstBoolean("verified");
|
||||||
|
if(TypeIsString(oldname) && TypeIsString(newname))
|
||||||
|
{
|
||||||
|
|
||||||
|
const userInfo = DB.GetAccountInfo(oldname);
|
||||||
|
|
||||||
|
if(TypeIsDictionary(userInfo))
|
||||||
|
{
|
||||||
|
var flags = ParseLong(userInfo.flags);
|
||||||
|
//CREATE TABLE IF NOT EXISTS accounts
|
||||||
|
//(id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT UNIQUE, accountName TEXT UNIQUE,
|
||||||
|
//password_hash TEXT, password_salt TEXT, motto TEXT, verifyKey TEXT UNIQUE,
|
||||||
|
//verifyExpire INTEGER, flags INTEGER, created INTEGER, verified INTEGER);
|
||||||
|
|
||||||
|
const wasVerified = (flags & DB.FLAG_VERIFIED) != 0;
|
||||||
|
|
||||||
|
if(userInfo.accountName != active.text)
|
||||||
|
{
|
||||||
|
if(!admin)
|
||||||
|
{
|
||||||
|
flags &= ~DB.FLAG_ADMIN;
|
||||||
|
}
|
||||||
|
if(!verified)
|
||||||
|
{
|
||||||
|
flags |= DB.FLAG_VERIFY;
|
||||||
|
flags &= ~DB.FLAG_VERIFIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(admin)
|
||||||
|
{
|
||||||
|
flags |= DB.FLAG_ADMIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(verified)
|
||||||
|
{
|
||||||
|
|
||||||
|
flags |= DB.FLAG_VERIFIED;
|
||||||
|
flags &= ~DB.FLAG_VERIFY;
|
||||||
|
}
|
||||||
|
|
||||||
|
DB.Lock();
|
||||||
|
const dbCon = DB.Open();
|
||||||
|
if(!wasVerified && verified)
|
||||||
|
{
|
||||||
|
Sqlite.Exec(dbCon, $"UPDATE accounts SET accountName = {Sqlite.Escape(newname)}, motto = {Sqlite.Escape(motto)}, flags = {Sqlite.Escape(flags)}, verified = {Sqlite.Escape(DateTime.NowEpoch ?? 0)} WHERE id = {Sqlite.Escape(userInfo.id)};");
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Sqlite.Exec(dbCon, $"UPDATE accounts SET accountName = {Sqlite.Escape(newname)}, motto = {Sqlite.Escape(motto)}, flags = {Sqlite.Escape(flags)} WHERE id = {Sqlite.Escape(userInfo.id)};");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Sqlite.Close(dbCon);
|
||||||
|
DB.Unlock();
|
||||||
|
|
||||||
|
|
||||||
|
ctx.StatusCode=303;
|
||||||
|
ctx.ResponseHeaders.SetValue("Location", "/admin_accounts");
|
||||||
|
return Shell("Redirect",pages,
|
||||||
|
<null>
|
||||||
|
<h1>Redirecting</h1>
|
||||||
|
Click <a href="/admin_accounts">here</a> if it does not redirect
|
||||||
|
</null>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.StatusCode=400;
|
||||||
|
return Shell("Must need a user",pages,
|
||||||
|
<null>
|
||||||
|
<h1>Must need a user</h1>
|
||||||
|
Click <a href="/admin_accounts">here</a> to go back to admin list
|
||||||
|
</null>
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ctx.StatusCode = 401; return Shell("Invalid CSRF", pages,<h1>Invalid CSRF</h1>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const name = ctx.QueryParams.TryGetFirst("account");
|
||||||
|
const page = ctx.QueryParams.TryGetFirstInt("page") ?? 1;
|
||||||
|
var cur = (page - 1) % 3;
|
||||||
|
var firstPage = (page-1) - cur;
|
||||||
|
var userInfo = null;
|
||||||
|
var motto_ta = "";
|
||||||
|
const list = [];
|
||||||
|
|
||||||
|
if(active.admin && TypeIsString(name))
|
||||||
|
{
|
||||||
|
userInfo = DB.GetAccountInfo(name);
|
||||||
|
if(!TypeIsDictionary(userInfo))
|
||||||
|
{
|
||||||
|
if(TypeIsString(userInfo) && userInfo == "No such user exists")
|
||||||
|
ctx.StatusCode = 404;
|
||||||
|
else
|
||||||
|
ctx.StatusCode = 500;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
csrf = DB.CreateCSRF(ctx);
|
||||||
|
motto_ta = TypeOf(userInfo.motto) == "String" ? userInfo.motto : "";
|
||||||
|
userInfo.flags = ParseLong(userInfo.flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(active.admin && !TypeIsString(name))
|
||||||
|
{
|
||||||
|
const limit = 20;
|
||||||
|
DB.Lock();
|
||||||
|
const db = DB.Open();
|
||||||
|
const res = Sqlite.Exec(db, $"SELECT * FROM accounts LIMIT {Sqlite.Escape(limit)} OFFSET {Sqlite.Escape((page-1)*limit)};");
|
||||||
|
Sqlite.Close(db);
|
||||||
|
DB.Unlock();
|
||||||
|
|
||||||
|
if(TypeIsList(res))
|
||||||
|
{
|
||||||
|
each(var item in res)
|
||||||
|
{
|
||||||
|
const flags = ParseLong(item.flags);
|
||||||
|
|
||||||
|
|
||||||
|
list.Add({
|
||||||
|
name = item.accountName,
|
||||||
|
created = new DateTime(ParseLong(item.created)).ToString("%Y/%m/%d %H:%M:%S UTC"),
|
||||||
|
verified = (flags & DB.FLAG_VERIFIED) ? (new DateTime(ParseLong(item.verified)).ToString("%Y/%m/%d %H:%M:%S UTC")) : "N/A",
|
||||||
|
admin = (flags & DB.FLAG_ADMIN) ? "Yes" : "No"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ctx.StatusCode = 500;
|
||||||
|
return Shell("Error", pages,
|
||||||
|
<h1>Error {res}</h1>);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var html = <div class="container">
|
||||||
|
|
||||||
|
<if(active.admin)>
|
||||||
|
<true>
|
||||||
|
<if(TypeIsString(name))>
|
||||||
|
<true>
|
||||||
|
<if(TypeIsDictionary(userInfo))>
|
||||||
|
<true>
|
||||||
|
<form method="POST" action="./admin_accounts">
|
||||||
|
<input type="hidden" name="csrf" value={csrf}>
|
||||||
|
<input type="hidden" name="oldname" value={name}>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="name" class="form-label">Name</label>
|
||||||
|
<input type="text" class="form-control" id="name" name="newname" value={name}>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="motto" class="form-label">Motto</label>
|
||||||
|
<if(motto_ta.Length == 0)>
|
||||||
|
<true><textarea class="form-control" id="motto" name="motto" placeholder="Type your motto and/or links here" id="floatingTextarea2" style="height: 100px"></textarea></true>
|
||||||
|
<false><textarea class="form-control" id="motto" name="motto" placeholder="Type your motto and/or links here" id="floatingTextarea2" style="height: 100px">{motto_ta}</textarea></false>
|
||||||
|
</if>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<if(userInfo.flags & DB.FLAG_VERIFIED)>
|
||||||
|
<true>
|
||||||
|
<if(userInfo.accountName == active.text)>
|
||||||
|
<true>
|
||||||
|
<input class="form-check-input" type="checkbox" name="verified" id="verified" checked="ON" disabled="ON">
|
||||||
|
</true>
|
||||||
|
<false>
|
||||||
|
<input class="form-check-input" type="checkbox" name="verified" id="verified" checked="ON">
|
||||||
|
</false>
|
||||||
|
</if>
|
||||||
|
</true>
|
||||||
|
<false>
|
||||||
|
<input class="form-check-input" type="checkbox" name="verified" id="verified">
|
||||||
|
</false>
|
||||||
|
</if>
|
||||||
|
<label class="form-check-label" for="verified">
|
||||||
|
Is Verified
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<if(userInfo.flags & DB.FLAG_ADMIN)>
|
||||||
|
<true>
|
||||||
|
<if(userInfo.accountName == active.text)>
|
||||||
|
<true>
|
||||||
|
<input class="form-check-input" type="checkbox" name="admin" id="admin" checked="ON" disabled="ON">
|
||||||
|
</true>
|
||||||
|
<false>
|
||||||
|
<input class="form-check-input" type="checkbox" name="admin" id="admin" checked="ON">
|
||||||
|
</false>
|
||||||
|
</if>
|
||||||
|
</true>
|
||||||
|
<false>
|
||||||
|
<input class="form-check-input" type="checkbox" name="admin" id="admin">
|
||||||
|
</false>
|
||||||
|
</if>
|
||||||
|
<label class="form-check-label" for="admin">
|
||||||
|
Is Admin
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary" name="action">Save</button>
|
||||||
|
<a href="./admin_accounts" class="btn btn-secondary">Back</a>
|
||||||
|
</form>
|
||||||
|
</true>
|
||||||
|
<false>
|
||||||
|
<h1>Error {userInfo}</h1>
|
||||||
|
</false>
|
||||||
|
</if>
|
||||||
|
</true>
|
||||||
|
<false>
|
||||||
|
|
||||||
|
<a href="./admin" class="btn btn-primary">Back To Admin</a>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">Name</th>
|
||||||
|
<th scope="col">Created</th>
|
||||||
|
<th scope="col">Verified</th>
|
||||||
|
<th scope="col">Admin</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<each(var item : list)>
|
||||||
|
<tr>
|
||||||
|
<th scope="row"><a href={$"./admin_accounts?account={Net.Http.UrlEncode(item.name)}"}>{item.name}</a></th>
|
||||||
|
<td>{item.created}</td>
|
||||||
|
<td>{item.verified}</td>
|
||||||
|
<td>{item.admin}</td>
|
||||||
|
</tr>
|
||||||
|
</each>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<nav aria-label="Page navigation example">
|
||||||
|
<ul class="pagination justify-content-center">
|
||||||
|
<if(page == 1)>
|
||||||
|
<true>
|
||||||
|
<li class="page-item disabled">
|
||||||
|
<a class="page-link">Previous</a>
|
||||||
|
</li>
|
||||||
|
</true>
|
||||||
|
<false>
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href={$"./admin_accounts?page={page-1}"}>Previous</a>
|
||||||
|
</li>
|
||||||
|
</false>
|
||||||
|
</if>
|
||||||
|
<for(var i = 1; i <= 3; i++)>
|
||||||
|
|
||||||
|
<li class={i == cur + 1 ? "page-item active" : "page-item"}><a class="page-link" href={$"./admin_accounts?page={i+firstPage}"}>{i+firstPage}</a></li>
|
||||||
|
</for>
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href={$"./admin_accounts?page={page+1}"}>Next</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</false>
|
||||||
|
</if>
|
||||||
|
</true>
|
||||||
|
<false>
|
||||||
|
<h1>You are not authorized in the admin panel</h1>
|
||||||
|
</false>
|
||||||
|
</if>
|
||||||
|
</div>;
|
||||||
|
|
||||||
|
return Shell("Admin Register", pages,html);
|
||||||
|
}
|
||||||
@@ -31,7 +31,7 @@ func Pages.AdminRegister(ctx)
|
|||||||
var displayName = ctx.QueryParams.TryGetFirst("displayName");
|
var displayName = ctx.QueryParams.TryGetFirst("displayName");
|
||||||
var password = ctx.QueryParams.TryGetFirst("password");
|
var password = ctx.QueryParams.TryGetFirst("password");
|
||||||
var confirm = ctx.QueryParams.TryGetFirst("confirm");
|
var confirm = ctx.QueryParams.TryGetFirst("confirm");
|
||||||
var flags = ctx.QueryParams.GetFirstBoolean("verified") ? DB.FLAG_VERIFIED : DB.FLAG_FLAG_VERIFY;
|
var flags = ctx.QueryParams.GetFirstBoolean("verified") ? DB.FLAG_VERIFIED : DB.FLAG_VERIFY;
|
||||||
flags |= (ctx.QueryParams.GetFirstBoolean("admin") ? DB.FLAG_ADMIN : 0);
|
flags |= (ctx.QueryParams.GetFirstBoolean("admin") ? DB.FLAG_ADMIN : 0);
|
||||||
|
|
||||||
if(TypeOf(email) != "String" || TypeOf(displayName) != "String" || TypeOf(password) != "String" || TypeOf(confirm) != "String")
|
if(TypeOf(email) != "String" || TypeOf(displayName) != "String" || TypeOf(password) != "String" || TypeOf(confirm) != "String")
|
||||||
|
|||||||
@@ -14,10 +14,20 @@ func Pages.CheckEmail(ctx)
|
|||||||
DB.LoginButton(ctx,false)
|
DB.LoginButton(ctx,false)
|
||||||
];
|
];
|
||||||
var html = <div class={"container"}>
|
var html = <div class={"container"}>
|
||||||
<h1>Please check your email.</h1>
|
<if(DB.Config.MailConfig)>
|
||||||
<p>
|
<true>
|
||||||
The email may or may not be in your spam.
|
<h1>Please check your email.</h1>
|
||||||
</p>
|
<p>
|
||||||
|
The email may or may not be in your spam.
|
||||||
|
</p>
|
||||||
|
</true>
|
||||||
|
<false>
|
||||||
|
<h1>The admin will need to verify your account</h1>
|
||||||
|
<p>
|
||||||
|
Mail is disabled
|
||||||
|
</p>
|
||||||
|
</false>
|
||||||
|
</if>
|
||||||
</div>;
|
</div>;
|
||||||
return Shell("Check your email",pages,html);
|
return Shell(DB.Config.MailConfig ? "Check your email" : "Admin will need to verify",pages,html);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
func Pages.CreateSession(ctx)
|
||||||
|
{
|
||||||
|
var active = DB.LoginButton(ctx,false,"");
|
||||||
|
|
||||||
|
var pages = [
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/packages",
|
||||||
|
text = "Packages"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/upload",
|
||||||
|
text = "Upload"
|
||||||
|
},
|
||||||
|
active
|
||||||
|
];
|
||||||
|
|
||||||
|
const account = DB.GetUserIdFromSession(active.session);
|
||||||
|
|
||||||
|
if(TypeIsDictionary(account))
|
||||||
|
{
|
||||||
|
if(ctx.Method == "GET")
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
return Shell("Create API Key", pages,
|
||||||
|
<div class="container">
|
||||||
|
<h1>Create session</h1>
|
||||||
|
<form method="POST" action="./create_session">
|
||||||
|
<input type="hidden" name="csrf" value={DB.CreateCSRF(ctx)}>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="name" class="form-label">Session Name</label>
|
||||||
|
<input type="text" class="form-control" id="name" name="name" placeholder="Session Name">
|
||||||
|
</div>
|
||||||
|
<input type="submit" class="btn btn-primary" value="Create">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if(ctx.Method == "POST")
|
||||||
|
{
|
||||||
|
var name = ctx.QueryParams.TryGetFirst("name") ?? "CrossLang Shell";
|
||||||
|
var csrf = ctx.QueryParams.TryGetFirst("csrf");
|
||||||
|
|
||||||
|
if(!DB.VerifyCSRF(active.session,csrf))
|
||||||
|
return Shell("Invalid CSRF", pages, "<h1>Invalid CSRF</h1>");
|
||||||
|
|
||||||
|
|
||||||
|
return Shell("Your API key", pages,
|
||||||
|
<div class="container">
|
||||||
|
<h1>Your API key</h1>
|
||||||
|
<p>{"It won't be shown again"}</p>
|
||||||
|
<div class="mb-3 row">
|
||||||
|
<label for="apiKey" class="col-sm-2 col-form-label">API Key</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" readonly="ON" class="form-control-plaintext" id="apiKey" value={DB.CreateSession(account.accountId,false,name)}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Shell("Error", pages, "<h1>Not logged in</h1>");
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
func Pages.Index(ctx)
|
func Pages.Index(ctx)
|
||||||
{
|
{
|
||||||
var repo = TypeOf(DB.Config.RepoCommitPrefix) == "String" ? DB.Config.RepoCommitPrefix : "https://onedev.site.tesses.net/crosslang/crosslangextras/~files/";
|
var repo = TypeOf(DB.Config.RepoCommitPrefix) == "String" ? DB.Config.RepoCommitPrefix : "https://git.tesses.org/tesses50/crosslangextras/src/commit/";
|
||||||
|
|
||||||
var pages = [
|
var pages = [
|
||||||
{
|
{
|
||||||
|
|||||||
74
Tesses.CrossLang.PackageServer/src/pages/session.tcross
Normal file
74
Tesses.CrossLang.PackageServer/src/pages/session.tcross
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
func Pages.Session(ctx)
|
||||||
|
{
|
||||||
|
var active = DB.LoginButton(ctx,false,"");
|
||||||
|
|
||||||
|
var pages = [
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/packages",
|
||||||
|
text = "Packages"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/upload",
|
||||||
|
text = "Upload"
|
||||||
|
},
|
||||||
|
active
|
||||||
|
];
|
||||||
|
|
||||||
|
const account = DB.GetUserIdFromSession(active.session);
|
||||||
|
const id = ctx.QueryParams.TryGetFirstInt("id");
|
||||||
|
if(TypeIsDictionary(account) && TypeIsLong(id))
|
||||||
|
{
|
||||||
|
if(ctx.Method == "GET")
|
||||||
|
{
|
||||||
|
DB.Lock();
|
||||||
|
const dbCon = DB.Open();
|
||||||
|
const results = Sqlite.Exec(dbCon, $"SELECT * FROM sessions WHERE accountId = {Sqlite.Escape(account.accountId)} AND id = {Sqlite.Escape(id)};");
|
||||||
|
Sqlite.Close(dbCon);
|
||||||
|
DB.Unlock();
|
||||||
|
|
||||||
|
return Shell("Delete session?", pages, <if(TypeIsList(results) && results.Count == 1)>
|
||||||
|
<true>
|
||||||
|
<div class="container">
|
||||||
|
<h1>Do you want to delete session: {results[0].name}?</h1>
|
||||||
|
<p>Created: {new DateTime(ParseLong(results[0].created) ?? 0).ToString("%Y/%m/%d %H:%M:%S UTC")}</p>
|
||||||
|
<p>Expires: {results[0].expires == "0" ? "Won't" : new DateTime(ParseLong(results[0].expires) ?? 0).ToString("%Y/%m/%d %H:%M:%S UTC")}</p>
|
||||||
|
<p>Type: {results[0].key == active.session ? "This Session" : results[0].expires == "0" ? "API Key" : "Browser"}</p>
|
||||||
|
<form method="POST" action="./session">
|
||||||
|
<input type="hidden" name="csrf" value={DB.CreateCSRF(ctx)}>
|
||||||
|
<input type="hidden" name="id" value={id}>
|
||||||
|
<input type="submit" class="btn btn-danger" name="confirm" value="Yes">
|
||||||
|
<input type="submit" class="btn btn-primary" name="confirm" value="No">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</true>
|
||||||
|
</if>);
|
||||||
|
}
|
||||||
|
else if(ctx.Method == "POST")
|
||||||
|
{
|
||||||
|
var confirm = ctx.QueryParams.TryGetFirst("confirm") ?? "No";
|
||||||
|
|
||||||
|
if(confirm == "Yes")
|
||||||
|
{
|
||||||
|
var csrf = ctx.QueryParams.TryGetFirst("csrf");
|
||||||
|
|
||||||
|
if(!DB.VerifyCSRF(active.session,csrf))
|
||||||
|
return Shell("Invalid CSRF", pages, "<h1>Invalid CSRF</h1>");
|
||||||
|
|
||||||
|
DB.Lock();
|
||||||
|
const dbCon = DB.Open();
|
||||||
|
Sqlite.Exec(dbCon, $"DELETE FROM sessions WHERE accountId = {Sqlite.Escape(account.accountId)} AND id = {Sqlite.Escape(id)};");
|
||||||
|
Sqlite.Close(dbCon);
|
||||||
|
DB.Unlock();
|
||||||
|
}
|
||||||
|
ctx.StatusCode = 303;
|
||||||
|
ctx.ResponseHeaders.SetValue("Location", "./sessions");
|
||||||
|
return Shell("Redirecting", pages,<null>
|
||||||
|
<h1>Redirecting</h1>
|
||||||
|
Click <a href="./sessions">here</a> if it does not redirect
|
||||||
|
</null>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Shell("Error", pages, "<h1>Not logged in</h1>");
|
||||||
|
}
|
||||||
62
Tesses.CrossLang.PackageServer/src/pages/sessions.tcross
Normal file
62
Tesses.CrossLang.PackageServer/src/pages/sessions.tcross
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
func Pages.Sessions(ctx)
|
||||||
|
{
|
||||||
|
var active = DB.LoginButton(ctx,false,"");
|
||||||
|
|
||||||
|
var pages = [
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/packages",
|
||||||
|
text = "Packages"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active = false,
|
||||||
|
route = "/upload",
|
||||||
|
text = "Upload"
|
||||||
|
},
|
||||||
|
active
|
||||||
|
];
|
||||||
|
|
||||||
|
const account = DB.GetUserIdFromSession(active.session);
|
||||||
|
|
||||||
|
if(TypeIsDictionary(account))
|
||||||
|
{
|
||||||
|
DB.Lock();
|
||||||
|
const dbCon = DB.Open();
|
||||||
|
const results = Sqlite.Exec(dbCon, $"SELECT * FROM sessions WHERE accountId = {Sqlite.Escape(account.accountId)};");
|
||||||
|
Sqlite.Close(dbCon);
|
||||||
|
DB.Unlock();
|
||||||
|
|
||||||
|
return Shell("Sessions",
|
||||||
|
pages,
|
||||||
|
<div class="container">
|
||||||
|
<a href="./create_session" class="btn btn-primary">Create API Key</a>
|
||||||
|
<if(TypeIsList(results))>
|
||||||
|
<true>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">Name</th>
|
||||||
|
<th scope="col">Created</th>
|
||||||
|
<th scope="col">Expires</th>
|
||||||
|
<th scope="col">Type</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<each(var item : results)>
|
||||||
|
<tr>
|
||||||
|
<th scope="row"><a href={$"./session?id={Net.Http.UrlEncode(item.id)}"}>{item.name}</a></th>
|
||||||
|
<td>{new DateTime(ParseLong(item.created) ?? 0).ToString("%Y/%m/%d %H:%M:%S UTC")}</td>
|
||||||
|
<td>{item.expires == "0" ? "Won't" : new DateTime(ParseLong(item.expires) ?? 0).ToString("%Y/%m/%d %H:%M:%S UTC")}</td>
|
||||||
|
<td>{item.key == active.session ? "This Session" : item.expires == "0" ? "API Key" : "Browser"}</td>
|
||||||
|
</tr>
|
||||||
|
</each>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</true>
|
||||||
|
</if>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Shell("You are not logged in",pages,<h1>You are not logged in</h1>);
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
func main(args)
|
func main(args)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
var dir = ".";
|
var dir = ".";
|
||||||
if(args.Length > 1)
|
if(args.Length > 1)
|
||||||
{
|
{
|
||||||
@@ -7,6 +9,14 @@ func main(args)
|
|||||||
}
|
}
|
||||||
DB.Init(dir);
|
DB.Init(dir);
|
||||||
|
|
||||||
|
const timer = new Timer(()=>{
|
||||||
|
const time = DateTime.NowEpoch ?? 0;
|
||||||
|
DB.Lock();
|
||||||
|
const db = DB.Open();
|
||||||
|
Sqlite.Exec(db, "DELETE FROM sessions WHERE expires < {time} AND expires > 0;");
|
||||||
|
Sqlite.Close(db);
|
||||||
|
DB.Unlock();
|
||||||
|
},900000);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -14,7 +24,7 @@ func main(args)
|
|||||||
PUT /api/v1/upload Authorization Bearer
|
PUT /api/v1/upload Authorization Bearer
|
||||||
POST /api/v1/login Json object with email and password returns json object with either 200 for success {"token": "TOKEN_VAL"} or non 2XX if fails {"reason": "SOME ERROR"}
|
POST /api/v1/login Json object with email and password returns json object with either 200 for success {"token": "TOKEN_VAL"} or non 2XX if fails {"reason": "SOME ERROR"}
|
||||||
POST /api/v1/logout use Authorization Bearer
|
POST /api/v1/logout use Authorization Bearer
|
||||||
GET /api/v1/latest?name=PackageName returns 200 OK with json {"version": "1.0.0.0-prod"} if it succeeds if it fails returns a failing status code with {"reason": "SOME ERROR"}
|
GET /api/v1/latest?name=PackageName returns 200 OK with json {"version":"1.0.0.0-dev"} if it succeeds if it fails returns a failing status code with {"reason": "SOME ERROR"}
|
||||||
GET /api/v1/download?name=PackageName&version=1.0.0.0-prod returns 200 OK with package bytes or 404 if doesn't exist
|
GET /api/v1/download?name=PackageName&version=1.0.0.0-prod returns 200 OK with package bytes or 404 if doesn't exist
|
||||||
GET /api/v1/search?q=SomeQuery&offset=&limit= returns 200 OK with json of packages {"packages": [{"name": "pkgName","version": "latestVersion", ...}]} or non success status code
|
GET /api/v1/search?q=SomeQuery&offset=&limit= returns 200 OK with json of packages {"packages": [{"name": "pkgName","version": "latestVersion", ...}]} or non success status code
|
||||||
|
|
||||||
@@ -41,6 +51,11 @@ func main(args)
|
|||||||
ctx.WithMimeType("text/html").SendText(Pages.AdminRegister(ctx));
|
ctx.WithMimeType("text/html").SendText(Pages.AdminRegister(ctx));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if(ctx.Path == "/admin_accounts")
|
||||||
|
{
|
||||||
|
ctx.WithMimeType("text/html").SendText(Pages.AdminAccount(ctx));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if(ctx.Path == "/package")
|
if(ctx.Path == "/package")
|
||||||
{
|
{
|
||||||
var name = ctx.QueryParams.TryGetFirst("name");
|
var name = ctx.QueryParams.TryGetFirst("name");
|
||||||
@@ -137,9 +152,9 @@ func main(args)
|
|||||||
|
|
||||||
if(DB.VerifyCSRF(session,csrf))
|
if(DB.VerifyCSRF(session,csrf))
|
||||||
{
|
{
|
||||||
var userId = DB.GetUserIdFromSession(session);
|
var userId = DB.GetUserIdFromSession(session).accountId;
|
||||||
var url = DB.ChangeMotto(userId,motto);
|
var url = DB.ChangeMotto(userId,motto);
|
||||||
ctx.StatusCode = 302;
|
ctx.StatusCode = 303;
|
||||||
ctx.ResponseHeaders.SetValue("Location", url);
|
ctx.ResponseHeaders.SetValue("Location", url);
|
||||||
ctx.WithMimeType("text/html").SendText(<null>
|
ctx.WithMimeType("text/html").SendText(<null>
|
||||||
<h1>Redirecting</h1>
|
<h1>Redirecting</h1>
|
||||||
@@ -194,7 +209,7 @@ func main(args)
|
|||||||
|
|
||||||
if(!DB.VerifyCSRF(session,csrf))
|
if(!DB.VerifyCSRF(session,csrf))
|
||||||
{
|
{
|
||||||
var userId = DB.GetUserIdFromSession(session);
|
var userId = DB.GetUserIdFromSession(session).accountId;
|
||||||
result = DB.UploadPackage(userId, filePath);
|
result = DB.UploadPackage(userId, filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +218,7 @@ func main(args)
|
|||||||
|
|
||||||
if(result.Success)
|
if(result.Success)
|
||||||
{
|
{
|
||||||
ctx.StatusCode = 302;
|
ctx.StatusCode = 303;
|
||||||
ctx.ResponseHeaders.SetValue("Location", "/");
|
ctx.ResponseHeaders.SetValue("Location", "/");
|
||||||
ctx.WithMimeType("text/html").SendText(<null>
|
ctx.WithMimeType("text/html").SendText(<null>
|
||||||
<h1>Redirecting</h1>
|
<h1>Redirecting</h1>
|
||||||
@@ -279,7 +294,7 @@ func main(args)
|
|||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
var userId = DB.GetUserIdFromSession(session);
|
var userId = DB.GetUserIdFromSession(session).accountId;
|
||||||
var filePath = DB.working / "Temp" / $"{DB.GetUniqueNumber()}.crvm";
|
var filePath = DB.working / "Temp" / $"{DB.GetUniqueNumber()}.crvm";
|
||||||
|
|
||||||
var strm = FS.Local.OpenFile(filePath,"wb");
|
var strm = FS.Local.OpenFile(filePath,"wb");
|
||||||
@@ -335,7 +350,7 @@ func main(args)
|
|||||||
|
|
||||||
|
|
||||||
ctx.SendJson({
|
ctx.SendJson({
|
||||||
token = DB.CreateSession(accountId)
|
token = DB.CreateSession(accountId,false, TypeIsString(json.name) ? json.name : "CrossLang Shell")
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -432,13 +447,16 @@ func main(args)
|
|||||||
if(accountId == -1)
|
if(accountId == -1)
|
||||||
{
|
{
|
||||||
ctx.StatusCode = 400;
|
ctx.StatusCode = 400;
|
||||||
ctx.SendText("<h1>Invalid credentials</h1>");
|
ctx.SendText(Shell("Invalid credentials",[],"<h1>Invalid credentials</h1>"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.StatusCode = 302;
|
ctx.StatusCode = 303;
|
||||||
ctx.ResponseHeaders.SetValue("Location", "/");
|
ctx.ResponseHeaders.SetValue("Location", "/");
|
||||||
ctx.ResponseHeaders.SetValue("Set-Cookie", $"Session={DB.CreateSession(accountId)}; SameSite=Strict");
|
const browser="Browser";
|
||||||
|
const now = DateTime.NowEpoch??0;
|
||||||
|
|
||||||
|
ctx.ResponseHeaders.SetValue("Set-Cookie", $"Session={DB.CreateSession(accountId,true, browser)}; SameSite=Strict; Expires={new DateTime(now+DB.Expires).ToHttpDate()}");
|
||||||
ctx.WithMimeType("text/html").SendText(<null>
|
ctx.WithMimeType("text/html").SendText(<null>
|
||||||
<h1>Redirecting</h1>
|
<h1>Redirecting</h1>
|
||||||
Click <a href="./">here</a> if it does not redirect
|
Click <a href="./">here</a> if it does not redirect
|
||||||
@@ -492,7 +510,7 @@ func main(args)
|
|||||||
var res = DB.UnforgetPassword(code,password,confirm);
|
var res = DB.UnforgetPassword(code,password,confirm);
|
||||||
if(res.Success)
|
if(res.Success)
|
||||||
{
|
{
|
||||||
ctx.StatusCode = 302;
|
ctx.StatusCode = 303;
|
||||||
ctx.ResponseHeaders.SetValue("Location", "/");
|
ctx.ResponseHeaders.SetValue("Location", "/");
|
||||||
ctx.WithMimeType("text/html").SendText(<null>
|
ctx.WithMimeType("text/html").SendText(<null>
|
||||||
<h1>Redirecting</h1>
|
<h1>Redirecting</h1>
|
||||||
@@ -538,7 +556,7 @@ func main(args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ctx.StatusCode = 302;
|
ctx.StatusCode = 303;
|
||||||
ctx.ResponseHeaders.SetValue("Location", res.Redirect);
|
ctx.ResponseHeaders.SetValue("Location", res.Redirect);
|
||||||
ctx.WithMimeType("text/html").SendText(<null>
|
ctx.WithMimeType("text/html").SendText(<null>
|
||||||
<h1>Redirecting</h1>
|
<h1>Redirecting</h1>
|
||||||
@@ -596,12 +614,12 @@ func main(args)
|
|||||||
if(!res.Success)
|
if(!res.Success)
|
||||||
{
|
{
|
||||||
ctx.StatusCode = 400;
|
ctx.StatusCode = 400;
|
||||||
ctx.SendText($"<h1>Error: {Net.Http.HtmlEncode(res.Reason)}</h1>");
|
ctx.SendText(Shell("Error",[],$"<h1>Error: {Net.Http.HtmlEncode(res.Reason)}</h1>"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ctx.StatusCode = 302;
|
ctx.StatusCode = 303;
|
||||||
ctx.ResponseHeaders.SetValue("Location", res.Redirect);
|
ctx.ResponseHeaders.SetValue("Location", res.Redirect);
|
||||||
ctx.WithMimeType("text/html").SendText(<null>
|
ctx.WithMimeType("text/html").SendText(<null>
|
||||||
<h1>Redirecting</h1>
|
<h1>Redirecting</h1>
|
||||||
@@ -615,6 +633,22 @@ func main(args)
|
|||||||
ctx.WithMimeType("text/html").SendText(Pages.Account(ctx));
|
ctx.WithMimeType("text/html").SendText(Pages.Account(ctx));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if(ctx.Path == "/sessions")
|
||||||
|
{
|
||||||
|
|
||||||
|
ctx.WithMimeType("text/html").SendText(Pages.Sessions(ctx));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(ctx.Path == "/create_session")
|
||||||
|
{
|
||||||
|
ctx.WithMimeType("text/html").SendText(Pages.CreateSession(ctx));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(ctx.Path == "/session")
|
||||||
|
{
|
||||||
|
ctx.WithMimeType("text/html").SendText(Pages.Session(ctx));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if(ctx.Path == "/css/bootstrap.min.css")
|
if(ctx.Path == "/css/bootstrap.min.css")
|
||||||
{
|
{
|
||||||
ctx.WithMimeType("text/css").SendBytes(embed("css/bootstrap.min.css"));
|
ctx.WithMimeType("text/css").SendBytes(embed("css/bootstrap.min.css"));
|
||||||
@@ -650,4 +684,6 @@ func main(args)
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
},DB.Port);
|
},DB.Port);
|
||||||
|
|
||||||
|
timer.Callback = null;
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ func VM.RunEventLoop()
|
|||||||
/^
|
/^
|
||||||
Merge all crvm files into one and returns path inside destVFS of output
|
Merge all crvm files into one and returns path inside destVFS of output
|
||||||
You should have srcFS a SubdirFilesystem to directory with executable
|
You should have srcFS a SubdirFilesystem to directory with executable
|
||||||
so if the source executable was /app/bin/app-1.0.0.0-prod.crvm you should pass a SubdirFilesystem pointing to the directory /app/bin and sourcePath set to /app-1.0.0.0-prod.crvm and destVFS to a empty SubdirFilesystem
|
so if the source executable was /app/bin/app-1.0.0.0-dev.crvm you should pass a SubdirFilesystem pointing to the directory /app/bin and sourcePath set to /app-1.0.0.0-dev.crvm and destVFS to a empty SubdirFilesystem
|
||||||
^/
|
^/
|
||||||
func VM.Merge(srcVFS,sourcePath,destVFS)
|
func VM.Merge(srcVFS,sourcePath,destVFS)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "Tesses.CrossLang.Shell",
|
"name": "Tesses.CrossLang.Shell",
|
||||||
"version": "1.0.0.0-prod",
|
"version": "1.0.0.0-dev",
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"info": {
|
"info": {
|
||||||
"maintainer": "Mike Nolan",
|
"maintainer": "Mike Nolan",
|
||||||
"type": "console",
|
"type": "console",
|
||||||
"repo": "https://onedev.site.tesses.net/CrossLang/CrossLangExtras",
|
"repo": "https://git.tesses.org/tesses50/crosslangextras",
|
||||||
"homepage": "https://crosslang.tesseslanguage.com/",
|
"homepage": "https://crosslang.tesseslanguage.com/",
|
||||||
"license": "LGPLv3"
|
"license": "LGPLv3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ func Tesses.CrossLang.Shell.Login(dd)
|
|||||||
var name = dd.Arguments[1];
|
var name = dd.Arguments[1];
|
||||||
|
|
||||||
var host = dd.Arguments[2];
|
var host = dd.Arguments[2];
|
||||||
|
Console.Write("Name (empty for CrossLang Shell): ");
|
||||||
|
var name = Console.ReadLine() ?? "";
|
||||||
|
if(name == "") name = "CrossLang Shell";
|
||||||
|
|
||||||
Console.Write("Email: ");
|
Console.Write("Email: ");
|
||||||
var email = Console.ReadLine();
|
var email = Console.ReadLine();
|
||||||
@@ -45,6 +48,7 @@ func Tesses.CrossLang.Shell.Login(dd)
|
|||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
|
|
||||||
var accountRequest = {
|
var accountRequest = {
|
||||||
|
name,
|
||||||
email,
|
email,
|
||||||
password
|
password
|
||||||
};
|
};
|
||||||
|
|||||||
168
Tesses.CrossLang.Shell/src/logout.tcross
Normal file
168
Tesses.CrossLang.Shell/src/logout.tcross
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
func Tesses.CrossLang.Shell.Logout(dd)
|
||||||
|
{
|
||||||
|
var accounts = [];
|
||||||
|
|
||||||
|
func help()
|
||||||
|
{
|
||||||
|
Console.WriteLine("USAGE: crosslang logout [name]");
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine("ARGUMENTS:");
|
||||||
|
Console.WriteLine("name: the session name");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(FS.Local.FileExists(Env.CrossLangConfig / "auth.json"))
|
||||||
|
{
|
||||||
|
accounts = Json.Decode(FS.ReadAllText(FS.Local,Env.CrossLangConfig / "auth.json"));
|
||||||
|
if(TypeOf(accounts) != "List") accounts = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dd.Flags.Contains("help"))
|
||||||
|
{
|
||||||
|
help();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(FS.Local.FileExists(Env.CrossLangConfig / "auth.json"))
|
||||||
|
{
|
||||||
|
const json = Json.Decode(FS.ReadAllText(FS.Local,Env.CrossLangConfig / "auth.json"));
|
||||||
|
if(json.Length == 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("You were not logged in");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if(json.Length == 1)
|
||||||
|
{
|
||||||
|
const host = json[0].host;
|
||||||
|
const token = json[0].token;
|
||||||
|
|
||||||
|
if(!TypeIsString(host))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Host is not a string");
|
||||||
|
FS.WriteAllText(FS.Local, Env.CrossLangConfig / "auth.json", "[]");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!TypeIsString(token))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Token is not a string");
|
||||||
|
FS.WriteAllText(FS.Local, Env.CrossLangConfig / "auth.json", "[]");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const resp = Net.Http.MakeRequest($"{host.TrimEnd('/')}/api/v1/logout",{
|
||||||
|
RequestHeaders = [
|
||||||
|
{Key= "Authorization",Value=$"Bearer {token}"}
|
||||||
|
],
|
||||||
|
Method = "GET"
|
||||||
|
});
|
||||||
|
|
||||||
|
if(resp.StatusCode == 200)
|
||||||
|
{
|
||||||
|
const json = resp.ReadAsJson();
|
||||||
|
if(json.Success)
|
||||||
|
{
|
||||||
|
|
||||||
|
FS.WriteAllText(FS.Local, Env.CrossLangConfig / "auth.json", "[]");
|
||||||
|
resp.Close();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
FS.WriteAllText(FS.Local, Env.CrossLangConfig / "auth.json", "[]");
|
||||||
|
resp.Close();
|
||||||
|
Console.WriteLine($"Failed to logout, go to {host.TrimEnd('/')}/sessions to logout");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.Close();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(dd.Arguments.Length < 2)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Multiple entries in auth.json file, session is ambiguous.");
|
||||||
|
Console.WriteLine("Sessions:");
|
||||||
|
each(var item : json)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{item.name}: {item.host}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var host = "";
|
||||||
|
var token = "";
|
||||||
|
var found = false;
|
||||||
|
var cur = null;
|
||||||
|
each(var item : json)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(item.name == dd.Arguments[1])
|
||||||
|
{
|
||||||
|
cur = item;
|
||||||
|
found=true;
|
||||||
|
host = item.host;
|
||||||
|
token = item.token;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!found) {
|
||||||
|
Console.WriteLine($"Could not find session with name: {dd.Arguments[1]}");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(!TypeIsString(host))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Host is not a string");
|
||||||
|
json.Remove(cur);
|
||||||
|
FS.WriteAllText(FS.Local, Env.CrossLangConfig / "auth.json", json.ToString());
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!TypeIsString(token))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Token is not a string");
|
||||||
|
json.Remove(cur);
|
||||||
|
FS.WriteAllText(FS.Local, Env.CrossLangConfig / "auth.json", json.ToString());
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const resp = Net.Http.MakeRequest($"{host.TrimEnd('/')}/api/v1/logout",{
|
||||||
|
RequestHeaders = [
|
||||||
|
{Key= "Authorization",Value=$"Bearer {token}"}
|
||||||
|
],
|
||||||
|
Method = "GET"
|
||||||
|
});
|
||||||
|
|
||||||
|
if(resp.StatusCode == 200)
|
||||||
|
{
|
||||||
|
const json2 = resp.ReadAsJson();
|
||||||
|
if(json2.Success)
|
||||||
|
{
|
||||||
|
json.Remove(cur);
|
||||||
|
FS.WriteAllText(FS.Local, Env.CrossLangConfig / "auth.json", json.ToString());
|
||||||
|
resp.Close();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
json.Remove(cur);
|
||||||
|
FS.WriteAllText(FS.Local, Env.CrossLangConfig / "auth.json", json.ToString());
|
||||||
|
resp.Close();
|
||||||
|
Console.WriteLine($"Failed to logout, go to {host.TrimEnd('/')}/sessions to logout");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.Close();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Console.WriteLine("You were not logged in");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -74,6 +74,7 @@ func Tesses.CrossLang.Shell.New(dd)
|
|||||||
var old_info = proj.info;
|
var old_info = proj.info;
|
||||||
proj.info = old_info.template_info;
|
proj.info = old_info.template_info;
|
||||||
proj.icon = old_info.template_icon;
|
proj.icon = old_info.template_icon;
|
||||||
|
proj.prebuild = old_info.template_prebuild;
|
||||||
proj.dependencies = old_info.template_project_dependencies;
|
proj.dependencies = old_info.template_project_dependencies;
|
||||||
var srcDir = proj.source_directory;
|
var srcDir = proj.source_directory;
|
||||||
if(TypeOf(srcDir) == "Undefined") srcDir = "/src";
|
if(TypeOf(srcDir) == "Undefined") srcDir = "/src";
|
||||||
@@ -105,7 +106,7 @@ func Tesses.CrossLang.Shell.New(dd)
|
|||||||
var src = FS.ReadAllText(projectDir, ent);
|
var src = FS.ReadAllText(projectDir, ent);
|
||||||
|
|
||||||
src = src.Replace("%PROJECT_NAME%",projectPath.GetFileName());
|
src = src.Replace("%PROJECT_NAME%",projectPath.GetFileName());
|
||||||
src = src.Replace("%TEMPLATE_PROJECT_NAME%","%PROJECT_NAME");
|
src = src.Replace("%TEMPLATE_PROJECT_NAME%","%PROJECT_NAME%");
|
||||||
|
|
||||||
FS.WriteAllText(projectDir, ent, src);
|
FS.WriteAllText(projectDir, ent, src);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
func Tesses.CrossLang.Shell.Token(dd)
|
func Tesses.CrossLang.Shell.Token(dd)
|
||||||
{
|
{
|
||||||
|
Console.Write("Name (empty for CrossLang Shell): ");
|
||||||
|
var name = Console.ReadLine() ?? "";
|
||||||
|
if(name == "") name = "CrossLang Shell";
|
||||||
Console.Write("Host: ");
|
Console.Write("Host: ");
|
||||||
var host = Console.ReadLine();
|
var host = Console.ReadLine();
|
||||||
Console.Write("Email: ");
|
Console.Write("Email: ");
|
||||||
@@ -15,6 +18,7 @@ func Tesses.CrossLang.Shell.Token(dd)
|
|||||||
|
|
||||||
|
|
||||||
var accountRequest = {
|
var accountRequest = {
|
||||||
|
name,
|
||||||
email,
|
email,
|
||||||
password
|
password
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,5 +4,5 @@
|
|||||||
"description": "The standard library of crosslang"
|
"description": "The standard library of crosslang"
|
||||||
},
|
},
|
||||||
"name": "Tesses.CrossLang.Std",
|
"name": "Tesses.CrossLang.Std",
|
||||||
"version": "1.0.0.0-prod"
|
"version": "1.0.0.0-dev"
|
||||||
}
|
}
|
||||||
|
|||||||
45
build.tcross
45
build.tcross
@@ -14,7 +14,7 @@ func cmd(name, args)
|
|||||||
func main(args)
|
func main(args)
|
||||||
{
|
{
|
||||||
|
|
||||||
var args2=["-o","./Tesses.CrossLang.BuildEssentials/bin-tmp","-r","./Tesses.CrossLang.BuildEssentials/res","-n","Tesses.CrossLang.BuildEssentials","-v","1.0.0.0-prod","Tesses.CrossLang.BuildEssentials/main.tcross"];
|
var args2=["-o","./Tesses.CrossLang.BuildEssentials/bin-tmp","-r","./Tesses.CrossLang.BuildEssentials/res","-n","Tesses.CrossLang.BuildEssentials","-v","1.0.0.0-dev","Tesses.CrossLang.BuildEssentials/main.tcross"];
|
||||||
each(var f : FS.Local.EnumeratePaths("./Tesses.CrossLang.BuildEssentials/src"))
|
each(var f : FS.Local.EnumeratePaths("./Tesses.CrossLang.BuildEssentials/src"))
|
||||||
{
|
{
|
||||||
if(f.GetExtension() == ".tcross")
|
if(f.GetExtension() == ".tcross")
|
||||||
@@ -22,38 +22,41 @@ func main(args)
|
|||||||
args2.Add(f.ToString());
|
args2.Add(f.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cmd("crossc", args2);
|
cmd("crossc", args2);
|
||||||
cmd("crossvm",["./Tesses.CrossLang.BuildEssentials/bin-tmp/Tesses.CrossLang.BuildEssentials-1.0.0.0-prod.crvm","Tesses.CrossLang.Shell"]);
|
cmd("crossvm",["./Tesses.CrossLang.BuildEssentials/bin-tmp/Tesses.CrossLang.BuildEssentials-1.0.0.0-dev.crvm","Tesses.CrossLang.Shell"]);
|
||||||
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-prod.crvm","build","Tesses.CrossLang.PackageServer"]);
|
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-dev.crvm","build","Tesses.CrossLang.PackageServer"]);
|
||||||
//cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-prod.crvm","build","Tesses.CrossLang.WebSite"]);
|
//cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-dev.crvm","build","Tesses.CrossLang.WebSite"]);
|
||||||
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-prod.crvm","build","Tesses.CrossLang.Std"]);
|
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-dev.crvm","build","Tesses.CrossLang.Std"]);
|
||||||
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-prod.crvm","build","Templates/console"]);
|
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-dev.crvm","build","Templates/console"]);
|
||||||
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-prod.crvm","build","Templates/emptyweb"]);
|
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-dev.crvm","build","Templates/emptyweb"]);
|
||||||
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-prod.crvm","build","Templates/web"]);
|
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-dev.crvm","build","Templates/web"]);
|
||||||
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-prod.crvm","build","Templates/template"]);
|
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-dev.crvm","build","Templates/template"]);
|
||||||
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-prod.crvm","build","Templates/lib"]);
|
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-dev.crvm","build","Templates/lib"]);
|
||||||
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-prod.crvm","build","Templates/compiletool"]);
|
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-dev.crvm","build","Templates/compiletool"]);
|
||||||
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-prod.crvm","build","Templates/tool"]);
|
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-dev.crvm","build","Templates/tool"]);
|
||||||
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-prod.crvm","build","Templates/webapp"]);
|
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-dev.crvm","build","Templates/webapp"]);
|
||||||
|
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-dev.crvm","build","Templates/npmweb"]);
|
||||||
|
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-dev.crvm","build","Templates/npmwebapp"]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-prod.crvm","build","Tesses.CrossLang.PackageServer"]);
|
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-dev.crvm","build","Tesses.CrossLang.PackageServer"]);
|
||||||
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-prod.crvm","build","Tesses.CrossLang.PackageServer"]);
|
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-dev.crvm","build","Tesses.CrossLang.PackageServer"]);
|
||||||
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-prod.crvm","build","Tesses.CrossLang.PackageServer"]);
|
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-dev.crvm","build","Tesses.CrossLang.PackageServer"]);
|
||||||
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-prod.crvm","build","Tesses.CrossLang.PackageServer"]);
|
|
||||||
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-prod.crvm","build","Tesses.CrossLang.PackageServer"]);
|
|
||||||
*/
|
*/
|
||||||
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-prod.crvm","build","crosslang_shell_archive_maker"]);
|
cmd("crossvm",["./Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-dev.crvm","build","crosslang_shell_archive_maker"]);
|
||||||
|
|
||||||
if(args.Length > 1)
|
if(args.Length > 1)
|
||||||
{
|
{
|
||||||
if(args[1] == "install")
|
if(args[1] == "install")
|
||||||
{
|
{
|
||||||
cmd("crossvm",["crosslang_shell_archive_maker/bin/crosslang_shell_archive_maker-1.0.0.0-prod.crvm", "install"]);
|
cmd("crossvm",["crosslang_shell_archive_maker/bin/crosslang_shell_archive_maker-1.0.0.0-dev.crvm", "install"]);
|
||||||
}
|
}
|
||||||
else if(args[1] == "pack")
|
else if(args[1] == "pack")
|
||||||
{
|
{
|
||||||
cmd("crossvm",["crosslang_shell_archive_maker/bin/crosslang_shell_archive_maker-1.0.0.0-prod.crvm"]);
|
cmd("crossvm",["crosslang_shell_archive_maker/bin/crosslang_shell_archive_maker-1.0.0.0-dev.crvm"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,5 +6,5 @@
|
|||||||
"project_dependencies": [
|
"project_dependencies": [
|
||||||
"..\/Tesses.CrossLang.BuildEssentials"
|
"..\/Tesses.CrossLang.BuildEssentials"
|
||||||
],
|
],
|
||||||
"version": "1.0.0.0-prod"
|
"version": "1.0.0.0-dev"
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
var name = "Tesses.CrossLang.ShellPackage-1.0.0.0-prod.crvm";
|
var name = "Tesses.CrossLang.ShellPackage-1.0.0.0-dev.crvm";
|
||||||
func main(args)
|
func main(args)
|
||||||
{
|
{
|
||||||
create_archive();
|
create_archive();
|
||||||
@@ -23,7 +23,9 @@ func install()
|
|||||||
func create_archive()
|
func create_archive()
|
||||||
{
|
{
|
||||||
|
|
||||||
var tmpFS = new SubdirFilesystem(FS.Local,"crosslang_shell_archive_maker/tmp");
|
var tmpFS = new SubdirFilesystem(FS.Local,FS.MakeFull("crosslang_shell_archive_maker/tmp"));
|
||||||
|
|
||||||
|
|
||||||
func copyFile(src,dest)
|
func copyFile(src,dest)
|
||||||
{
|
{
|
||||||
if(!FS.Local.FileExists(src)) return;
|
if(!FS.Local.FileExists(src)) return;
|
||||||
@@ -41,9 +43,9 @@ func create_archive()
|
|||||||
|
|
||||||
tmpFS.CreateDirectory(shell);
|
tmpFS.CreateDirectory(shell);
|
||||||
|
|
||||||
copyFile("Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Args-1.0.0.0-prod.crvm", shell / "Tesses.CrossLang.Args-1.0.0.0-prod.crvm");
|
copyFile("Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Args-1.0.0.0-dev.crvm", shell / "Tesses.CrossLang.Args-1.0.0.0-dev.crvm");
|
||||||
copyFile("Tesses.CrossLang.Shell/bin/Tesses.CrossLang.BuildEssentials-1.0.0.0-prod.crvm", shell / "Tesses.CrossLang.BuildEssentials-1.0.0.0-prod.crvm");
|
copyFile("Tesses.CrossLang.Shell/bin/Tesses.CrossLang.BuildEssentials-1.0.0.0-dev.crvm", shell / "Tesses.CrossLang.BuildEssentials-1.0.0.0-dev.crvm");
|
||||||
copyFile("Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-prod.crvm", shell / "Shell.crvm");
|
copyFile("Tesses.CrossLang.Shell/bin/Tesses.CrossLang.Shell-1.0.0.0-dev.crvm", shell / "Shell.crvm");
|
||||||
copyFile("Tesses.CrossLang.Reference/bin/Tesses.CrossLang.Reference-1.0.0.0-dev.crvm", "Reference.crvm");
|
copyFile("Tesses.CrossLang.Reference/bin/Tesses.CrossLang.Reference-1.0.0.0-dev.crvm", "Reference.crvm");
|
||||||
var devStudio = r / "DevStudio";
|
var devStudio = r / "DevStudio";
|
||||||
tmpFS.CreateDirectory(devStudio);
|
tmpFS.CreateDirectory(devStudio);
|
||||||
@@ -66,14 +68,16 @@ func create_archive()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
copyFile("Templates/compiletool/bin/Tesses.CrossLang.Template.CompileTool-1.0.0.0-prod.crvm", templates / "compiletool.crvm");
|
copyFile("Templates/compiletool/bin/Tesses.CrossLang.Template.CompileTool-1.0.0.0-dev.crvm", templates / "compiletool.crvm");
|
||||||
copyFile("Templates/console/bin/Tesses.CrossLang.Template.Console-1.0.0.0-prod.crvm", templates / "console.crvm");
|
copyFile("Templates/console/bin/Tesses.CrossLang.Template.Console-1.0.0.0-dev.crvm", templates / "console.crvm");
|
||||||
copyFile("Templates/lib/bin/Tesses.CrossLang.Template.Library-1.0.0.0-prod.crvm", templates / "lib.crvm");
|
copyFile("Templates/lib/bin/Tesses.CrossLang.Template.Library-1.0.0.0-dev.crvm", templates / "lib.crvm");
|
||||||
copyFile("Templates/template/bin/Tesses.CrossLang.Template.Template-1.0.0.0-prod.crvm", templates / "template.crvm");
|
copyFile("Templates/template/bin/Tesses.CrossLang.Template.Template-1.0.0.0-dev.crvm", templates / "template.crvm");
|
||||||
copyFile("Templates/web/bin/Tesses.CrossLang.Template.Website-1.0.0.0-prod.crvm", templates / "web.crvm");
|
copyFile("Templates/web/bin/Tesses.CrossLang.Template.Website-1.0.0.0-dev.crvm", templates / "web.crvm");
|
||||||
copyFile("Templates/emptyweb/bin/Tesses.CrossLang.Template.EmptyWebsite-1.0.0.0-prod.crvm", templates / "emptyweb.crvm");
|
copyFile("Templates/emptyweb/bin/Tesses.CrossLang.Template.EmptyWebsite-1.0.0.0-dev.crvm", templates / "emptyweb.crvm");
|
||||||
copyFile("Templates/tool/bin/Tesses.CrossLang.Template.Tool-1.0.0.0-prod.crvm", templates / "tool.crvm");
|
copyFile("Templates/tool/bin/Tesses.CrossLang.Template.Tool-1.0.0.0-dev.crvm", templates / "tool.crvm");
|
||||||
copyFile("Templates/webapp/bin/Tesses.CrossLang.Template.WebApp-1.0.0.0-prod.crvm", templates / "webapp.crvm");
|
copyFile("Templates/webapp/bin/Tesses.CrossLang.Template.WebApp-1.0.0.0-dev.crvm", templates / "webapp.crvm");
|
||||||
|
copyFile("Templates/npmwebapp/bin/Tesses.CrossLang.Template.NPMWebApp-1.0.0.0-dev.crvm", templates / "npmwebapp.crvm");
|
||||||
|
copyFile("Templates/npmweb/bin/Tesses.CrossLang.Template.NPMWebsite-1.0.0.0-dev.crvm", templates / "npmweb.crvm");
|
||||||
|
|
||||||
var packageCache = r / "PackageCache";
|
var packageCache = r / "PackageCache";
|
||||||
|
|
||||||
@@ -82,18 +86,18 @@ func create_archive()
|
|||||||
tmpFS.CreateDirectory(packageCache / "Tesses.CrossLang.BuildEssentials");
|
tmpFS.CreateDirectory(packageCache / "Tesses.CrossLang.BuildEssentials");
|
||||||
tmpFS.CreateDirectory(packageCache / "Tesses.CrossLang.Markup");
|
tmpFS.CreateDirectory(packageCache / "Tesses.CrossLang.Markup");
|
||||||
tmpFS.CreateDirectory(packageCache / "Tesses.CrossLang.Std");
|
tmpFS.CreateDirectory(packageCache / "Tesses.CrossLang.Std");
|
||||||
copyFile("Tesses.CrossLang.Args/bin/Tesses.CrossLang.Args-1.0.0.0-prod.crvm", packageCache / "Tesses.CrossLang.Args" / "1.0.0.0-prod");
|
copyFile("Tesses.CrossLang.Args/bin/Tesses.CrossLang.Args-1.0.0.0-dev.crvm", packageCache / "Tesses.CrossLang.Args" / "1.0.0.0-prod");
|
||||||
copyFile("Tesses.CrossLang.BuildEssentials/bin/Tesses.CrossLang.BuildEssentials-1.0.0.0-prod.crvm", packageCache / "Tesses.CrossLang.BuildEssentials" / "1.0.0.0-prod");
|
copyFile("Tesses.CrossLang.BuildEssentials/bin/Tesses.CrossLang.BuildEssentials-1.0.0.0-dev.crvm", packageCache / "Tesses.CrossLang.BuildEssentials" / "1.0.0.0-prod");
|
||||||
//copyFile("Tesses.CrossLang.Markup/bin/Tesses.CrossLang.Markup-1.0.0.0-prod.crvm", packageCache / "Tesses.CrossLang.Markup" / "1.0.0.0-prod");
|
//copyFile("Tesses.CrossLang.Markup/bin/Tesses.CrossLang.Markup-1.0.0.0-dev.crvm", packageCache / "Tesses.CrossLang.Markup" / "1.0.0.0-prod");
|
||||||
copyFile("Tesses.CrossLang.Args/bin/Tesses.CrossLang.Args-1.0.0.0-prod.crvm", packageCache / "Tesses.CrossLang.Args" / "1.0.0.0-prod");
|
copyFile("Tesses.CrossLang.Args/bin/Tesses.CrossLang.Args-1.0.0.0-dev.crvm", packageCache / "Tesses.CrossLang.Args" / "1.0.0.0-prod");
|
||||||
copyFile("Tesses.CrossLang.Std/bin/Tesses.CrossLang.Std-1.0.0.0-prod.crvm", packageCache / "Tesses.CrossLang.Std" / "1.0.0.0-prod");
|
copyFile("Tesses.CrossLang.Std/bin/Tesses.CrossLang.Std-1.0.0.0-dev.crvm", packageCache / "Tesses.CrossLang.Std" / "1.0.0.0-prod");
|
||||||
|
|
||||||
var installer = FS.Local.OpenFile(name, "wb");
|
var installer = FS.Local.OpenFile(name, "wb");
|
||||||
|
|
||||||
var ifo = {
|
var ifo = {
|
||||||
type = "archive",
|
type = "archive",
|
||||||
maintainer = "Mike Nolan",
|
maintainer = "Mike Nolan",
|
||||||
repo = "https://onedev.site.tesses.net/CrossLang/CrossLangExtras",
|
repo = "https://git.tesses.org/tesses50/crosslangextras",
|
||||||
homepage = "https://crosslang.tesseslanguage.com/"
|
homepage = "https://crosslang.tesseslanguage.com/"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
console: a console application (or webserver)
|
console: a console application (or webserver)
|
||||||
lib: a library
|
lib: a library
|
||||||
webapp: A web app (for webview or eventual cloud OS)
|
webapp: A web app (for webview or android, can specify port on cli)
|
||||||
template: used for project templates
|
template: used for project templates
|
||||||
compile_tool: run before source is compiled for project if it is in the dependency tree for the project (and is not linked to said projects)
|
compile_tool: run before source is compiled for project if it is in the dependency tree for the project (and is not linked to said projects)
|
||||||
tool: a tool invokable via crosslang (gets Tesses.CrossLang.Args for free)
|
tool: a tool invokable via crosslang (gets Tesses.CrossLang.Args for free)
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
"vscode": "^1.107.0"
|
"vscode": "^1.107.0"
|
||||||
},
|
},
|
||||||
"publisher": "tesses50",
|
"publisher": "tesses50",
|
||||||
"repository": "https://onedev.site.tesses.net/crosslang/crosslangextras",
|
"repository": "https://git.tesses.org/tesses50/crosslangextras",
|
||||||
"categories": [
|
"categories": [
|
||||||
"Programming Languages"
|
"Programming Languages"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -202,6 +202,7 @@ export async function createTemplate()
|
|||||||
if(project_name)
|
if(project_name)
|
||||||
{
|
{
|
||||||
const dir = join(getDocumentsFolder(),"CrossLangProjects",project_name);
|
const dir = join(getDocumentsFolder(),"CrossLangProjects",project_name);
|
||||||
|
mkdirSync(getDocumentsFolder());
|
||||||
mkdirSync(join(getDocumentsFolder(),"CrossLangProjects"));
|
mkdirSync(join(getDocumentsFolder(),"CrossLangProjects"));
|
||||||
mkdirSync(dir);
|
mkdirSync(dir);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user