massive update

This commit is contained in:
Michael Becker 2023-11-11 20:28:45 -05:00
parent a0dcc72d8c
commit 73d1bffea8
146 changed files with 3993 additions and 165 deletions

61
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,61 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: SUV Manager",
"type": "python",
"request": "launch",
"program": "./common/admin/suv-manager/python/SUVManager.py",
"console": "integratedTerminal",
"justMyCode": true
},
{
"name": "SUV Manager Debug",
"type": "php",
"request": "launch",
"runtimeArgs": [
"-S",
"localhost:8000",
"-t",
"./common/admin/suv-manager/php"
],
"port": 9003,
"serverReadyAction": {
"action": "openExternally"
}
},
{
"name": "Launch built-in server and debug",
"type": "php",
"request": "launch",
"runtimeArgs": [
"-S",
"localhost:8000",
"-t",
"."
],
"port": 9003,
"serverReadyAction": {
"action": "openExternally"
}
},
{
"name": "Debug current script in console",
"type": "php",
"request": "launch",
"program": "${file}",
"cwd": "${fileDirname}",
"externalConsole": false,
"port": 9003
},
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003
}
]
}

View File

@ -0,0 +1,24 @@
-----BEGIN CERTIFICATE-----
MIIEFTCCAv2gAwIBAgIUGVh9x6Y4ze81e4NO6vIW6IbkZ2UwDQYJKoZIhvcNAQEL
BQAwgZkxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJGTDEQMA4GA1UEBwwHT3JsYW5k
bzEfMB0GA1UECgwWTUJTIEJ1c2luZXNzIFNvbHV0aW9uczEkMCIGA1UEAwwbTUJT
IEludGVybmFsIERldmVsb3BtZW50IENBMSQwIgYJKoZIhvcNAQkBFhVzdXBwb3J0
QHRldHJvbmljYS5jb20wHhcNMjMxMTA3MTI0MjA5WhcNMjgxMTA2MTI0MjA5WjCB
mTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkZMMRAwDgYDVQQHDAdPcmxhbmRvMR8w
HQYDVQQKDBZNQlMgQnVzaW5lc3MgU29sdXRpb25zMSQwIgYDVQQDDBtNQlMgSW50
ZXJuYWwgRGV2ZWxvcG1lbnQgQ0ExJDAiBgkqhkiG9w0BCQEWFXN1cHBvcnRAdGV0
cm9uaWNhLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALtVx/bN
VbVzOyhqMxZQHiSMm8AaALTi5lMRWaKQNQuxazh6u8rwAv4IEvKGUdE8YSO3Dl3z
825d5KTeRLDPNOUr5bm8Xsg4x8StAwZYYknAnzqb629I0PmqCnsfshpA9kGy0UOz
vYOUMaTIDJpGrSlbUrh8RLDw5iVA6YL06DbZ+ooneriHtFmLcGUn8ENw596IBrxd
Xo5nHE51j3vtnF3get0taPCqZZy91mnB00i0iKRKtSFITzfUUDVJ34uL9aPXoEa0
CQvAsj6/MEtvSj5QTjuXOolRgZ/L4axfxfGNi76onrn0/d+dAvGIj0rZWYMzmPss
Z+6gYswTQ1pCi7UCAwEAAaNTMFEwHQYDVR0OBBYEFKQPCzyVOvt2fqdTNrCX+BLk
naLcMB8GA1UdIwQYMBaAFKQPCzyVOvt2fqdTNrCX+BLknaLcMA8GA1UdEwEB/wQF
MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAIy9g7cK6/lpYuuBZ1AwVR85uq/mZJWD
QJnoDjWtsI81yEe4SdHILcDncbNDoR/gZZGXUgiF8P6RGWMOluQOf4SUq5CRbnUT
T4aa3mWHGNs7Ixa+BohHFzM1AEljxa7kEM2MZ3Iv5/XNCwS9xP0sU+iu93oiwq4G
J9Co3Qt49GnJpUCs4rGAOVVCVCPD7vxDgm2PSTIvHQnr2RKheyDVCidiNTSZoLr4
SSYNMZ5jgB3upvD6cnbH9N/a6ZnoUjdXpotf2RUIbbQwVVusS0fcqTLC4pg4/69C
r8yurdutDzS5b+L+aShK6rJbn2zvgw0hBiz8hBrpVfu3kRpF73a+0y4=
-----END CERTIFICATE-----

View File

@ -0,0 +1,3 @@
These are self-signed certificates signed by the CA-MBS-DEV (MBS Internal Development CA) certificate.
You should probably replace them with your own secure certificates when hosting your production environment.

View File

@ -0,0 +1,29 @@
-----BEGIN CERTIFICATE-----
MIIE7zCCA9egAwIBAgIURvpBSseeEDIKEO0c1VBMWkLexMQwDQYJKoZIhvcNAQEL
BQAwgZkxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJGTDEQMA4GA1UEBwwHT3JsYW5k
bzEfMB0GA1UECgwWTUJTIEJ1c2luZXNzIFNvbHV0aW9uczEkMCIGA1UEAwwbTUJT
IEludGVybmFsIERldmVsb3BtZW50IENBMSQwIgYJKoZIhvcNAQkBFhVzdXBwb3J0
QHRldHJvbmljYS5jb20wHhcNMjMxMTA3MTI0MjMyWhcNMjUxMTA2MTI0MjMyWjBo
MQswCQYDVQQGEwJVUzELMAkGA1UECAwCRkwxEDAOBgNVBAcMB09ybGFuZG8xHzAd
BgNVBAoMFk1CUyBCdXNpbmVzcyBTb2x1dGlvbnMxGTAXBgNVBAMMECoucHJpdmF0
ZXN1di5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCB79lGqz1t
wC5KDJ6TMsJk6/BK7vQiyT3umuut2RPhwkMHfihz+zfxaYo4C7KHkSoCPT4v3u1y
MONJfiev8E+/ZzHlPNYhxs/Su1iSavJQHPvKzKMSkvjbMQFX/Cqzp/A2NL5EkmYv
HrFd9WiV2azp5knQ8hLWdvWR8gUHJZK0FocKA6qbQNQ3G/McOsEsaUZtjCcb1oJw
fKt4G8i2Iv0aMMTOJfCQYhrpuGuX8qkcD1gR9imb8qhthiLw54LwcrtQcIVEwFAG
YyDPVRsw6xvLYHchRkx+DvRdgy/UKMha9tq/3lzF9Fm1/3cnelEsKe7W51ZGkU+3
apVqNovaYZ+ty1rRxMe/tj4XtHaOLTioG/UMT7AL0LK3darEAS29n8UdT+xORBsU
7iENL112ZcY4yrzCDzUz1Ys0NJAl9a4p6kW33lu0idRTq75xwOYoKhX69Kff0bF8
dAAebxZSYcIF9/uKHpKW31zK8ac9d1bHYnkL8Ej2yA6Ps98tYLDUecC3dbYk+k2I
igz2BN2UhyEonb5DUz6dSlR+RR3kB884ycMrBi9FNEhjBhm5+iOHs1nAh1Hzm/IJ
Koiw49XyWZIxNYWkcqq9h4wQEQIiZ/3S1FeJWxj+vt+tZKAhDc71V5kSHHJXCh3X
EIqXLZYKXPAG0uST+H8VY5bXahKW/A60UQIDAQABo18wXTAbBgNVHREEFDASghAq
LnByaXZhdGVzdXYuY29tMB0GA1UdDgQWBBSCn5UhCbR7QG5M5RgZXI4y4LoFSDAf
BgNVHSMEGDAWgBSkDws8lTr7dn6nUzawl/gS5J2i3DANBgkqhkiG9w0BAQsFAAOC
AQEAPozqKZadO7QR4HxdU2KNuBlfbvZ62KS2UoiISnUS/cHEejkSdU6RaWN1wVv4
rimBhhVX+vkIBcd4OiaRTxFBQpgkyTxI7L+B/fKTmwUP3KEl2GSiWFwmAcRQjn4u
tNuABnn7d7UTl9NCR/n3981A1gl6cIAjv6XBEuDWCCTSCVWgWDBlpG2OA0Fp5+GL
J4Jl7xfjpiFAdOllVi/Cd63DiQmv6Fxuc2wBeugatLYCM8Mu6WOJ8+SvbJ57zYec
1oWftLmRr5WxpgGrbDMcAwwD74OXlTOuNX/Jx7uX2Y4Qlqysl7gHJtztlTQCO+23
RRiyHDf6iKxeh2S16xnVi2vtWw==
-----END CERTIFICATE-----

View File

@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
MIIJQAIBADANBgkqhkiG9w0BAQEFAASCCSowggkmAgEAAoICAQCB79lGqz1twC5K
DJ6TMsJk6/BK7vQiyT3umuut2RPhwkMHfihz+zfxaYo4C7KHkSoCPT4v3u1yMONJ
fiev8E+/ZzHlPNYhxs/Su1iSavJQHPvKzKMSkvjbMQFX/Cqzp/A2NL5EkmYvHrFd
9WiV2azp5knQ8hLWdvWR8gUHJZK0FocKA6qbQNQ3G/McOsEsaUZtjCcb1oJwfKt4
G8i2Iv0aMMTOJfCQYhrpuGuX8qkcD1gR9imb8qhthiLw54LwcrtQcIVEwFAGYyDP
VRsw6xvLYHchRkx+DvRdgy/UKMha9tq/3lzF9Fm1/3cnelEsKe7W51ZGkU+3apVq
NovaYZ+ty1rRxMe/tj4XtHaOLTioG/UMT7AL0LK3darEAS29n8UdT+xORBsU7iEN
L112ZcY4yrzCDzUz1Ys0NJAl9a4p6kW33lu0idRTq75xwOYoKhX69Kff0bF8dAAe
bxZSYcIF9/uKHpKW31zK8ac9d1bHYnkL8Ej2yA6Ps98tYLDUecC3dbYk+k2Iigz2
BN2UhyEonb5DUz6dSlR+RR3kB884ycMrBi9FNEhjBhm5+iOHs1nAh1Hzm/IJKoiw
49XyWZIxNYWkcqq9h4wQEQIiZ/3S1FeJWxj+vt+tZKAhDc71V5kSHHJXCh3XEIqX
LZYKXPAG0uST+H8VY5bXahKW/A60UQIDAQABAoIB/3zxpdHOgm3b3qcAe3tlKTLi
WAMLbgwFIbMkRSa7wTfVFPSfhfFWIEqDXJAyr06sx+MKAO0HRaFdtoYfnl9lNUoC
cSLS3RVIQjmLl3Uzts2nu8xxT7MMoJTPtVBlqqoWqBAiUiid808GtIck9EHOjqGw
+kob0awTDRAfKQvg6rCWTkPS7WVcxrOMrLj4cR3DcsrkJLcgDfhx6RrAR2rcj4TK
YHSFBvh6CGcLGcAtbBpkpstJablgx5SJkg+/OVRSVCGFZqDgTBMtlDR0zIYS4yct
cLW5DiopNya0fx6uGKVfufkbA8VWBu3QOUOSMCZyLA16EKbKvrIgSzdW5s7su3LZ
f+wNcsaYuUx7iWSyHVRz9zKkfnikphuPjIbF+gLmQYsLp+5jAt/NVnS045cilNbD
QQGoGQaArz7xYoCO2slT5ppAkFq7+z1heBFKJ2BbA3uZTE4EhEZipqDTn+Rk08O3
jm+KwUcl69odk8XoL6EKIfFeu/F8qRNnsTzlEhXCi6jsyfbMSUckvrZMfQQmDDHG
WzqbkCv7MJ1gtZpo8eME87lhSYQrXKeXHlnNpFg/eZxkLgm60+zZiJ48rvrJ/Ga5
mzL2NxgT4qZGljQMuloP93vsfd67A9Z3ELaTYUcqP+Le8sdbZs84rgMl0XYQZtRp
JlGkYn3UR0Rkm/xeR18CggEBALdrLz9KkaqNvi5sdcjh4Iwb4dsZx7o84nMhzN90
9MdVaQUKQ9JT3hek8l+CSMlXFGK2eQ96ZUXbFdqnZFvD73inHUX/dx+cnwuvIzjs
IhZK6XYIqZ3oI5xQSNiFk6C/J4r+ZWrUtwdZZKCASRInDlvg4kMJxFDtRoR9wb1H
sdcIjyM3PNArVGaNkBETBekdmsOMV5jo5D4l3GiXVCWB9HKAokxvo1v0T7h7P1S8
guyY3W/wLwERW7hjJ8JMT0UsWq9QjTdNTiMnS9B/qlalnO3S0WxvRTxtQnqNd6Cj
YM+Y37DBVLrERYehGUz0/2fUVdzoJYtEC+ow4iCAmDyncM8CggEBALVa0DmIzD55
KwgHzDvyOYn+ntEdr+0VjLBjyITcMX0pva9gl3xpLKHroXBXqa+q91SwYgz3oLMA
SFYiLwdCF5bc5lojGvW9tlQZljEVlTvFsKmpMQVZE0SclMnHonugbeRsFd4CATkK
gX2YxXDXdpTLfC0mQlrFL3cIAoNfGn4DHfQWVZ17CkRnzY4DxfBGyzhuO9dSqLV9
kX+iI/PB88hC+WM/euRqGOY0/F+7yyyCSlu3SlT+gF7G7xxe8n2kNc55zl1s+eub
pcCygGsys5r25BIL3gXyQozs3XNQIWWnZtALgITkkyPgD/72uZ4Rk1gb6S73/q3O
5HhSrzcRkN8CggEASvMFj3tNIsBg4l93keqa8yXBmOJj9vpCHoHFUdpc28dO7rxP
Encq3caNM/HtBDkNH3ko5uZA09a+i2azX7wk8sx27c+CQeyiIQgkAHKdSza5R34q
sVfWlV1JJxEOTjVOV0G0936Me/hPYjaJpV1IRMsUKginq9oJYsJwlIPja9cXhnBf
7UCHcJCQOinn1GZAg3+pm9YuziZydlrAC8Oau99Mcqd7vWuL1/qk2l9dsIiWk9M1
od4R+Lqr2H2ONtn1BIaJ7fss3riEBmLknBt4kMYAxaqCRDrxW1rLc1zPhoUVgwi9
MsRZFR8DU6sZYrgljetezBW2OLBY9qcVjlNtiQKCAQB4p+y0+pB4WAELHLUChQtH
BgH/urKbF6U8jYaQ7jZ2wViT372pZgftymjj507bsvFOhPMXEYD21o9JzwBe4dfz
5Q/UlFqReCBgH43PJj7dP49jsU8N8c9h7JMJFCrD+V5jhI2f4NGTc6vnNcbWZmNc
Z208VKH85gfIN6oEYTes8sHw7RMU7RFNpYoam+QLEe6Oorhpb3MTHHG66tLkj/tz
Fyv4nflTEktyjXoC71wjRqPWFUH8/j3F0LCwvXKzqJarwlpLyf8Ug79pTtkleNwJ
k4z1fLPAXQdt3wEOgRdXHGLIs35T7AcA7Ud3KAsiYSsYialAOHpWhLl4W/p6ttMd
AoIBAETFQ17eYJxPZH+Ai80+7RqBXJrb+fYgvTnvXmBoQRDcn4H89hcbw6e8I6on
/HZwB2YEw/sSoQhqC8mezGzHpqAAMJfmyhbjW/hHzErx5LlLayS8PhyDHA79RBRA
aCtPBgSyy3dp2cVfyslcBtV4qzjwSlp+SdUcUvvjNHP0SL6sKG4XHyzaoqsV7mI8
zEKPgsrP8SC5ezdrGtDXts6T2s2DCudJXb1FgiiyHofrAjhrRsHcbtn/cudHc+hK
fEf3oaNeOO/XfKZ3xkbHsbSlc+JsHEYVLkikm9Zu3ELJbxNw/Uq8H1sdFbT8Zkg+
Hn/DMWon80lSV4Ds8yHgx6W7Y/c=
-----END PRIVATE KEY-----

3
common/admin/generate-ca Normal file
View File

@ -0,0 +1,3 @@
#!/bin/sh
# usage: generate-ca CANAME
openssl req -x509 -new -nodes -key $1.key -sha256 -days 1826 -out $1.crt

17
common/admin/generate-ssc Normal file
View File

@ -0,0 +1,17 @@
#/bin/sh
# generates a self-signed certificate using openssl
CANAME=CA-MBS
CERTNAME=localhost
DOMAINNAME=*.privatesuv.com
if [ ! -f $CERTNAME.ext ]; then
echo "[SAN]
subjectAltName=DNS:$DOMAINNAME" > $CERTNAME.ext
fi
openssl req -extensions v3_req -new -addext "subjectAltName = DNS:$DOMAINNAME" -addext "keyUsage = digitalSignature,keyAgreement" -addext "extendedKeyUsage = serverAuth" -newkey rsa:4096 -sha256 -keyout $CERTNAME.key -nodes -out $CERTNAME.csr
openssl x509 -req -extensions SAN -extfile $CERTNAME.ext -in $CERTNAME.csr -CA $CANAME.crt -CAkey $CANAME.key -CAcreateserial -out $CERTNAME.crt -days 730 -sha256

View File

@ -0,0 +1,34 @@
import os
import sys
import zipfile
def zipdir(path, ziph):
# ziph is zipfile handle
for root, dirs, files in os.walk(path):
for file in files:
if file.endswith(".xml") or file == "manifest.inf":
ziph.write(os.path.join(root, file),
os.path.relpath(os.path.join(root, file),
os.path.join(path, '..')))
if len(sys.argv) > 1:
if sys.argv[1] == "build":
if len(sys.argv) > 2:
# usage: mocha lib build (folder) (filename.zip)
if len(sys.argv) > 3:
with zipfile.ZipFile(sys.argv[3], 'w', zipfile.ZIP_DEFLATED) as zipf:
zipdir(sys.argv[2], zipf)
else:
print ("usage: mocha lib build FILENAME")
else:
print ("usage: mocha lib build")
else:
print ("usage: mocha lib build")

View File

@ -0,0 +1,21 @@
#!/bin/bash
if [ $# -gt 0 ]; then
if [ -f "/usr/lib/mocha/mocha-$1" ]; then
MOCHA_COMMAND=$1
shift
exec "/usr/lib/mocha/mocha-$MOCHA_COMMAND" ${1+"$@"}
else
echo "mocha: '$1' is not a mocha command. See 'mocha --help'."
fi
else
echo "usage: mocha $(echo /usr/lib/mocha/mocha-* | sed -e 's/\/usr\/lib\/mocha\/mocha\-//g' -e 's/ /|/g')"
fi

View File

@ -0,0 +1,3 @@
#!/bin/sh
/usr/bin/python3 mocha-lib.py ${1+"$@"}

View File

@ -0,0 +1,166 @@
#!/bin/bash
MOCHA_DBNAME=$(cat /etc/mocha/dbname)
MOCHA_DBUSER=$(cat /etc/mocha/dbuser)
MOCHA_DBPASS=$(cat /etc/mocha/dbpass)
if [ ! -d ~/.config ]; then
mkdir ~/.config
fi
if [ ! -d ~/.config/mocha ]; then
mkdir ~/.config/mocha
fi
if [ -f ~/.config/mocha/tenant ]; then
CURRENT_TENANT=$(cat ~/.config/mocha/tenant)
#echo "current tenant: $CURRENT_TENANT"
#echo "use 'mocha oms tenant select' to change"
fi
if [ "$1" == "install" ]; then
if [ "$2" == "library" ]; then
echo "installing Mocha OMS from library '$3'..."
python3 /usr/lib/mocha/internal/mocha-install-library.py $3
else
echo "installing Mocha OMS from SQL..."
cd /usr/lib/mocha/sql/php
php ./install_mysql.php $MOCHA_DBNAME $MOCHA_DBUSER $MOCHA_DBPASS
fi
elif [ "$1" == "tenant" ]; then
if [ "$2" == "list" ]; then
mysql -D $MOCHA_DBNAME -u $MOCHA_DBUSER --password=$MOCHA_DBPASS -e "SELECT * FROM mocha_tenants"
elif [ "$2" == "create" ]; then
if [ $# -lt 3 ]; then
echo "usage: mocha oms tenant create TENANTNAME"
exit
fi
mysql -D $MOCHA_DBNAME -u $MOCHA_DBUSER --password=$MOCHA_DBPASS -e "CALL mocha_create_tenant('$3', NULL)"
elif [ "$2" == "delete" ]; then
if [ $# -lt 3 ]; then
echo "usage: mocha oms tenant delete TENANTNAME"
fi
if [ "$3" == "super" ]; then
echo "cannot delete the super tenant!"
exit
fi
mysql -D $MOCHA_DBNAME -u $MOCHA_DBUSER --password=$MOCHA_DBPASS -e "DELETE FROM mocha_tenants WHERE tenant_name = '$3'"
elif [ "$2" == "select" ]; then
if [ $# -lt 3 ]; then
echo "usage: mocha oms tenant select TENANTNAME"
exit
fi
echo $3 > ~/.config/mocha/tenant
echo "current tenant: $3"
elif [ "$2" == "release" ]; then
rm ~/.config/mocha/tenant
echo "current tenant: (none)"
fi
elif [ "$1" == "user" ]; then
if [ "$CURRENT_TENANT" == "" ]; then
echo "no tenant selected; please 'mocha oms tenant select' first"
exit
fi
if [ "$2" == "list" ]; then
mysql -D $MOCHA_DBNAME -u $MOCHA_DBUSER --password=$MOCHA_DBPASS -e "SELECT * FROM mocha_instances WHERE class_id = 39 AND tenant_id = mocha_get_tenant_by_name('$CURRENT_TENANT')";
elif [ "$2" == "set-password" ]; then
if [ "$3" == "" ]; then
echo "usage: mocha oms user set-password USERNAME [PASSWORD]"
exit
fi
PASSWORD=$4
if [ "$PASSWORD" == "" ]; then
echo "Changing password for $3."
stty -echo
read -p "New password: " PASSWORD
stty echo
echo ""
stty -echo
read -p "Retype new password: " PASSWORD2
stty echo
echo ""
echo ""
if [ "$PASSWORD" != "$PASSWORD2" ]; then
echo "Sorry, passwords do not match."
exit
fi
fi
PASSWORD_SALT=$(pwgen -s 128 -N 1)
PASSWORD_SALTED=$PASSWORD$PASSWORD_SALT
PASSWORD_HASH=$(php /usr/lib/mocha/sql/php/hash_pw.php $PASSWORD_SALTED)
# these two commands SHOULD execute atomically
# BUT for some reason this doesn't work on initial provisioning of the vagrant vm
# ........ for some reason, it works just fine when run manually though...
# oh well, it's not like anything is going to happen in the few picoseconds between calls...
mysql -D $MOCHA_DBNAME -u $MOCHA_DBUSER --password=$MOCHA_DBPASS -e "CALL mocha_set_attribute_value(mocha_get_tenant_by_name('$CURRENT_TENANT'), mocha_get_user_by_username('$3'), mocha_get_instance_by_global_identifier('F377FC294DF14AFB96434191F37A00A9'), '$PASSWORD_HASH', NULL, NULL)"
mysql -D $MOCHA_DBNAME -u $MOCHA_DBUSER --password=$MOCHA_DBPASS -e "CALL mocha_set_attribute_value(mocha_get_tenant_by_name('$CURRENT_TENANT'), mocha_get_user_by_username('$3'), mocha_get_instance_by_global_identifier('8C5A99BC40ED4FA2B23FF373C1F3F4BE'), '$PASSWORD_SALT', NULL, NULL)"
if [ $? -ne 0 ]; then
echo "mocha: password unchanged"
exit
fi
echo "mocha: password updated successfully"
exit
else
echo "usage: mocha oms user add|delete|lock|list|unlock|set-password"
fi
else
echo "usage: mocha oms tenant|user"
fi

View File

@ -0,0 +1,92 @@
#!/bin/bash
# mocha suv list
# mocha suv up
# mocha suv down
# mocha suv new
VAGRANT_MOCHADIR=/home/beckermj/Documents/Vagrant/mocha
VAGRANT_MACHINESDIR=$VAGRANT_MOCHADIR/machines
if [ "$1" == "list" ]; then
ls $VAGRANT_MACHINESDIR
elif [ "$1" == "up" ]; then
if [ "$2" != "" ]; then
MACHINEPATH=$VAGRANT_MACHINESDIR/$2
if [ -d "$MACHINEPATH" ]; then
cd $MACHINEPATH
vagrant up
else
echo "unknown machine named $2"
fi
else
echo "usage: mocha suv up MACHINENAME"
fi
elif [ "$1" == "down" ]; then
if [ "$2" != "" ]; then
MACHINEPATH=$VAGRANT_MACHINESDIR/$2
if [ -d "$MACHINEPATH" ]; then
cd $MACHINEPATH
vagrant halt
else
echo "unknown machine named $2"
fi
else
echo "usage: mocha suv down MACHINENAME"
fi
elif [ "$1" == "shell" ]; then
if [ "$2" != "" ]; then
MACHINEPATH=$VAGRANT_MACHINESDIR/$2
if [ -d "$MACHINEPATH" ]; then
cd $MACHINEPATH
vagrant ssh
else
echo "unknown machine named $2"
fi
else
echo "usage: mocha suv shell MACHINENAME"
fi
elif [ "$1" == "delete" ]; then
if [ "$2" != "" ]; then
MACHINEPATH=$VAGRANT_MACHINESDIR/$2
if [ -d "$MACHINEPATH" ]; then
cd $MACHINEPATH
vagrant destroy
if [ "$?" == "0" ]; then
rm -rf $MACHINEPATH
fi
else
echo "unknown machine named $2"
fi
else
echo "usage: mocha suv delete MACHINENAME"
fi
elif [ "$1" == "new" ]; then
cd $VAGRANT_MOCHADIR
if [ "$2" == "--transient" ]; then
./provision --transient
else
./provision
fi
else
echo "usage: mocha suv new [--transient] | (up|down|shell|delete MACHINENAME) | list"
fi

View File

@ -0,0 +1,66 @@
#!/bin/bash
FIRSTRUN=0
if [ -f "/etc/mocha/username" ]; then
MOCHA_USERNAME=$(cat /etc/mocha/username)
MOCHA_PASSWORD=$(cat /etc/mocha/userpass)
else
# we are running for the first time (or we are transient)
# generate a not-very-secure but easily-rememberable password for zq-developer
MOCHA_USERNAME="zq-developer"
MOCHA_PASSWORD=$(pwgen -N 1)
echo $MOCHA_USERNAME > /etc/mocha/username
echo $MOCHA_PASSWORD > /etc/mocha/userpass
MOCHA_DB_DATABASENAME="mocha_suv"
MOCHA_DB_USERNAME="mocha_suv"
# also generate a slightly more secure machine password for the mariadb database...
MOCHA_DB_PASSWORD=$(pwgen -s 32 -N 1)
# ... and add it to the configuration file
sed -i -e "s/@@MOCHA_DB_DATABASENAME@@/$MOCHA_DB_DATABASENAME/" -e "s/@@MOCHA_DB_USERNAME@@/$MOCHA_DB_USERNAME/" -e "s/@@MOCHA_DB_PASSWORD@@/$MOCHA_DB_PASSWORD/" /var/www/html/include/Configuration.inc.php
# ... and also add it to our local configuration
echo $MOCHA_DB_PASSWORD > /etc/mocha/dbpass
# don't forget to make a backup
cp /var/www/html/include/Configuration.inc.php /home/vagrant/html/include/Configuration.inc.php
# create the MySQL database and user with the previously generated password
mysql -e "DROP DATABASE IF EXISTS $MOCHA_DB_DATABASENAME; DROP USER IF EXISTS $MOCHA_DB_USERNAME;"
mysql -e "CREATE DATABASE $MOCHA_DB_DATABASENAME; CREATE USER $MOCHA_DB_USERNAME IDENTIFIED BY '$MOCHA_DB_PASSWORD'; GRANT ALL ON $MOCHA_DB_DATABASENAME.* TO '$MOCHA_DB_USERNAME'@'%';"
# install mocha using the `mocha oms` command
mocha oms install
mocha oms tenant select super
# set the new user name and password for the initial mocha user
mocha oms user set-password "$MOCHA_USERNAME" "$MOCHA_PASSWORD"
mocha oms tenant release
FIRSTRUN=1
fi
echo ""
echo "******************************************"
echo ""
echo "Thank you for provisioning your Mocha SUV!"
echo "You can log in with the following details:"
echo ""
echo "User name: $MOCHA_USERNAME"
echo "Password: $MOCHA_PASSWORD"
echo ""
echo "Your domain and IP address information is:"
echo ""
echo " $(hostname).privatesuv.com"
ip addr show dev enp0s8 | grep inet
echo ""
echo "******************************************"
echo ""
if [ $FIRSTRUN -eq 1 ]; then
# register the SUV for automatic shutdown in 10 hours
/usr/lib/mocha/spot_register_for_shutdown 600
fi

View File

@ -0,0 +1,3 @@
#!/bin/sh
echo "!!! This Spot Instance will automatically terminate in $1 minutes !!!"
shutdown -P +$1

Binary file not shown.

View File

@ -0,0 +1,4 @@
<?php
echo ("It works");
?>

View File

@ -0,0 +1,258 @@
from functools import cached_property
from http.cookies import SimpleCookie
from http.server import BaseHTTPRequestHandler
from urllib.parse import parse_qsl, urlparse
import json
from http.server import HTTPServer, BaseHTTPRequestHandler
class WebRequestHandler(BaseHTTPRequestHandler):
def __init__(self, request, client_address, server):
BaseHTTPRequestHandler.__init__(self, request, client_address, server)
@cached_property
def url(self):
return urlparse(self.path)
@cached_property
def query_data(self):
return dict(parse_qsl(self.url.query))
@cached_property
def post_data(self):
content_length = int(self.headers.get("Content-Length", 0))
return self.rfile.read(content_length)
@cached_property
def form_data(self):
return dict(parse_qsl(self.post_data.decode("utf-8")))
@cached_property
def cookies(self):
return SimpleCookie(self.headers.get("Cookie"))
def get_master_page_header(self, page_title):
return """<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>""" + page_title + """</title>
<link rel="stylesheet" type="text/css" href="/css/main.css" />
</head>
<body>"""
def get_master_page_footer(self):
return "</body></html>"
def write(self, text):
self.wfile.write(text.encode("utf-8"))
def write_file(self, filename):
with open(filename, mode='rb') as f:
lines = f.read()
self.wfile.write(lines)
def write_file_text(self, filename):
with open(filename, mode='r') as f:
lines = f.read()
self.wfile.write(lines.encode("utf-8"))
def execute_shell_return_stdout(self, command):
import os
p = os.popen(command)
ret = p.read()
return ret
def get_column_headings(self):
return [
'Instance ID',
'Description',
'State',
# Orch Manager
'Tenants',
'Info',
'Disposition Time',
'Up Time',
'Password',
'Actions'
]
def get_column_data(self, instanceId):
status = self.execute_shell_return_stdout("mocha suv status " + instanceId).split(':')
primaryStatus = status[0].strip()
secondaryStatus = ""
if len(status) > 1:
secondaryStatus = status[1].strip()
tenantsHtml = ""
tenantsStr = self.execute_shell_return_stdout("mocha suv shell " + instanceId + " -c 'mocha oms tenant list names'")
tenants = tenantsStr.split('\n')
for tenant in tenants:
if tenant != "":
tenantsHtml += "<a target=\"_blank\" href=\"https://" + instanceId + ".privatesuv.com/" + tenant + "\">" + tenant + " <i class=\"uwt-icon fa fa-arrow-up-right-from-square\"></i></a><br />"
startTimeStr = self.execute_shell_return_stdout("mocha suv shell " + instanceId + " -c 'cat /etc/mocha/suvstart'").strip()
print("startTimeStr = '" + startTimeStr + "'")
from datetime import datetime
startTime = datetime.fromisoformat(startTimeStr)
currentTime = datetime.now()
upTime = (currentTime - startTime)
from math import floor
secs = floor(upTime.seconds % 60)
mins = floor((upTime.seconds / 60) % 60)
hrs = floor((upTime.seconds / (60 * 60)) % 24)
upTimeStr = str(upTime.days) + "d " + str(hrs) + "h " + str(mins) + "m " + str(secs) + "s"
buttonsHtml = ""
if primaryStatus == "stopped":
buttonsHtml += "<a href=\"/my-suvs/" + instanceId + "/start\">Start</a>"
else:
buttonsHtml += "<a href=\"/my-suvs/" + instanceId + "/stop\">Stop</a>"
buttonsHtml += " <a href=\"/my-suvs/" + instanceId + "/restart\">Restart</a> <a href=\"/my-suvs/" + instanceId + "/terminate\">Terminate</a>"
return [
instanceId,
'None',
"<strong>" + primaryStatus + "</strong><br />" + secondaryStatus,
# "Orch Manager",
tenantsHtml,
"2023.11.10<br />master",
# Disposition Time
"Stops In: none",
# Up Time
"<!-- " + startTimeStr + " -->" + upTimeStr,
"<div style=\"text-align: center;\"><a href=\"#\"><i class=\"fa fa-key\"></i></a></div>",
buttonsHtml
]
def get_application_title(self) -> str:
return "SUV Manager"
def write_suv_entry(self, instanceId):
columns = self.get_column_data(instanceId)
self.write("<tr>")
for column in columns:
self.write("<td>" + column + "</td>")
self.write("</tr>")
def do_GET(self):
path = self.url.path.split('/')
path = path[1:]
if path[0] == "":
self.send_response(200)
self.send_header("Content-Type", "application/xhtml+xml")
self.end_headers()
self.write(self.get_master_page_header(self.get_application_title()))
self.write("<h1>It works</h1>")
self.write(self.get_master_page_footer())
elif path[0] == "css":
if path[1] == "main.css":
self.write_file_text("/usr/share/mocha/suv-manager/css/main.css")
elif path[0] == "common":
if path[1] == "fonts":
if path[2] == "awesome":
if path[3] == "css":
if path[4] == "all.min.css":
self.write_file("/usr/share/mocha/suv-manager/common/fonts/awesome/css/all.min.css")
elif path[3] == "webfonts":
self.write_file("/usr/share/mocha/suv-manager/common/fonts/awesome/webfonts/" + path[4])
elif path[0] == "my-suvs":
if (len(path) == 1 or (len(path) == 2 and path[1] == "")):
self.send_response(200)
self.send_header("Content-Type", "application/xhtml+xml")
self.end_headers()
self.write(self.get_master_page_header("My SUVs - " + self.get_application_title()))
self.write("""
<div class="uwt-panel">
<div class="uwt-content">
<h1>My SUVs</h1>
<div class="uwt-toolbar">
<a href="#" class="uwt-button uwt-color-primary"><i class="uwt-icon fa fa-add"></i><span class="uwt-title">Create SUV</span></a>
</div>
<table class="uwt-listview uwt-expand">
<thead>
<tr>""")
for column in self.get_column_headings():
self.write("<th> " + column + "</th>")
self.write("""</tr></thead><tbody>""")
suv_list = self.execute_shell_return_stdout("mocha suv list").split('\n')
for suv in suv_list:
if suv != "":
self.write_suv_entry(suv)
self.write("""
</tbody>
</table>
</div>
</div>
""")
self.write(self.get_master_page_footer())
elif len(path) == 2:
self.write("My SUVs SUV Page for " + path[1])
elif len(path) == 3:
if path[2] == "stop":
self.execute_shell_return_stdout("mocha suv down " + path[1])
self.send_response(302)
self.send_header("Location", "/my-suvs")
self.end_headers()
if path[2] == "start":
self.execute_shell_return_stdout("mocha suv up " + path[1])
self.send_response(302)
self.send_header("Location", "/my-suvs")
self.end_headers()
else:
self.write("My SUVs Action (" + path[2] + ") Page for " + path[1])
else:
self.send_response(404)
self.end_headers()
self.write("Not Found")
if __name__ == "__main__":
port = 61381
print("Mocha User Interface Service - running on port", port)
server = HTTPServer(("127.0.0.1", port), WebRequestHandler)
server.serve_forever()

67
common/admin/vagrant/provision Executable file
View File

@ -0,0 +1,67 @@
#!/bin/bash
# generate random UUID for new SUV
# thanks https://stackoverflow.com/questions/34328759
SUV_ID=$(hexdump -vn8 -e'2/4 "%08x" 1 "\n"' /dev/urandom)
SUV_NAME=i-0$SUV_ID
# *** DO NOT REMOVE THE FIRST DOT ***
SUV_DOMAINNAME=".privatesuv.com"
SUV_IP_FIRST=$(shuf -i 10-200 -n 1)
SUV_IP_LAST=$(shuf -i 10-200 -n 1)
SUV_IP=10.9.$SUV_IP_FIRST.$SUV_IP_LAST
SUV_ALWAYS_PROVISION="false"
if [ "$1" == "--transient" ]; then
shift
SUV_ALWAYS_PROVISION="true"
echo "initializing new TRANSIENT Mocha SUV with id $SUV_NAME"
else
echo "initializing new PERSISTENT Mocha SUV with id $SUV_NAME"
fi
SUV_TEMPLATE="default"
if [ "$1" != "" ]; then
SUV_TEMPLATE=$1
fi
if [ -d machines/$SUV_NAME ]; then
echo "machine with ID $SUV_NAME already provisioned"
exit;
fi
mkdir machines/$SUV_NAME
cd machines/$SUV_NAME
cp ../../templates/$SUV_TEMPLATE/$SUV_TEMPLATE.Vagrantfile ./Vagrantfile
cp ../../templates/$SUV_TEMPLATE/site.conf ./site.conf
cp ../../templates/$SUV_TEMPLATE/localhost.key .
cp ../../templates/$SUV_TEMPLATE/localhost.crt .
ln -s ../../templates/$SUV_TEMPLATE/mocha-libexec ./mocha-libexec
# cp ../../templates/default/default.box ./default.box
ln -s ../../templates/$SUV_TEMPLATE/sql ./sql
ln -s ../../templates/$SUV_TEMPLATE/site ./site
echo "enter sudo password to add entry to /etc/hosts if desired"
SUV_DNS=""
echo "$SUV_IP $SUV_NAME$SUV_DOMAINNAME" | sudo tee -a /etc/hosts
if [ $? == "0" ]; then
SUV_DNS="$SUV_NAME$SUV_DOMAINNAME"
fi
if [ "$SUV_DNS" != "" ]; then
SUV_IP_OR_DNS="$SUV_DNS"
else
SUV_IP_OR_DNS="$SUV_IP"
fi
sed -i -e "s/@@MOCHA_SUV_ID@@/$SUV_NAME/" -e "s/@@MOCHA_SUV_ADDRESS@@/$SUV_IP/" -e "s/@@MOCHA_SUV_HOSTNAME@@/$SUV_IP_OR_DNS/" -e "s/@@MOCHA_ALWAYS_PROVISION@@/$SUV_ALWAYS_PROVISION/" Vagrantfile
vagrant up

View File

@ -0,0 +1,196 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
# The most common configuration options are documented and commented below.
# For a complete reference, please see the online documentation at
# https://docs.vagrantup.com.
config.vm.define "@@MOCHA_SUV_ID@@" do |box|
# Every Vagrant development environment requires a box. You can search for
# boxes at https://vagrantcloud.com/search.
# box.vm.box = "mocha/lunar64"
box.vm.box = "ubuntu/lunar64"
#box.vm.box = "default.box"
box.vm.hostname = "@@MOCHA_SUV_ID@@.privatesuv.com"
# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs
# `vagrant box outdated`. This is not recommended.
# box.vm.box_check_update = false
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
# NOTE: This will enable public access to the opened port
# box.vm.network "forwarded_port", guest: 80, host: 8080
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine and only allow access
# via 127.0.0.1 to disable public access
# box.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
# Create a private network, which allows host-only access to the machine
# using a specific IP.
#box.vm.network "private_network", type: "dhcp"
box.vm.network "private_network", ip: "@@MOCHA_SUV_ADDRESS@@"
# Create a public network, which generally matched to bridged network.
# Bridged networks make the machine appear as another physical device on
# your network.
# box.vm.network "public_network"
# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
# box.vm.synced_folder "../data", "/vagrant_data"
# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose provider-specific options.
# Example for VirtualBox:
#
# box.vm.provider "virtualbox" do |vb|
# # Display the VirtualBox GUI when booting the machine
# vb.gui = true
#
# # Customize the amount of memory on the VM:
# vb.memory = "1024"
# end
#
# View the documentation for the provider you are using for more
# information on available options.
box.vm.provider "virtualbox" do |vb|
vb.name = "mochasuv-@@MOCHA_SUV_ID@@"
end
# Enable provisioning with a shell script. Additional provisioners such as
# Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
# documentation for more information about their specific syntax and use.
box.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y mariadb-server apache2 php php-mysql php-xml php-mbstring pwgen
# enable apache modules
a2enmod rewrite
a2enmod ssl
systemctl restart apache2
# ssh - for development only - REMOVE if publishing for public use
sed -e "s/KbdInteractiveAuthentication no/KbdInteractiveAuthentication yes/" /etc/ssh/sshd_config > /etc/ssh/sshd_config
systemctl restart ssh
# add webmasters group and webmaster user
addgroup webmasters
WEBMASTER_PASS="Solty/AyanamiREI^^96274"
useradd -G webmasters -p "$(openssl passwd -6 $WEBMASTER_PASS)" webmaster
SHELL
box.vm.provision "file", source: "site.conf", destination: "$HOME/mochadev.conf"
box.vm.provision "file", source: "localhost.key", destination: "$HOME/localhost.key"
box.vm.provision "file", source: "localhost.crt", destination: "$HOME/localhost.crt"
box.vm.provision "file", source: "mocha-libexec", destination: "$HOME/mocha-libexec"
box.vm.provision "file", source: "sql", destination: "$HOME/sql"
# initial provision of site
box.vm.provision "shell", inline: <<-SHELL
# **************************************************************
# SITE CONFIGURATION AND SSL
# **************************************************************
mv /home/vagrant/mochadev.conf /etc/apache2/sites-available/mochadev.conf
mv /home/vagrant/localhost.key /etc/ssl/certs
mv /home/vagrant/localhost.crt /etc/ssl/certs
# **************************************************************
# APACHE2 CONFIGURATION
# **************************************************************
# block port 80
sed -i -e "s/Listen 80/#Listen 80/" /etc/apache2/ports.conf
# disable default site and enable mochadev site
a2dissite 000-default
a2ensite mochadev
# reload configuration
systemctl reload apache2
# create peristent mocha configuration dir
mkdir /etc/mocha
mkdir /usr/lib/mocha
echo "mocha_suv" > /etc/mocha/dbname
echo "mocha_suv" > /etc/mocha/dbuser
mv /home/vagrant/mocha-libexec/mocha /usr/bin/mocha
mv /home/vagrant/mocha-libexec/mocha-* /usr/lib/mocha
mv /home/vagrant/mocha-libexec/internal /usr/lib/mocha
mv /home/vagrant/mocha-libexec/spot_register_for_shutdown /usr/lib/mocha
mv /home/vagrant/sql /usr/lib/mocha/sql
chmod a+x /usr/bin/mocha
chmod --recursive a+x /usr/lib/mocha
SHELL
# reset the site to the default upon launching the VM
# remove the run: "always" if you do not desire this behavior
box.vm.provision "file", source: "site", destination: "$HOME/html"
box.vm.provision "file", source: "site/.htaccess", destination: "$HOME/html/.htaccess"
box.vm.provision "shell", inline: <<-SHELL
if [ "@@MOCHA_ALWAYS_PROVISION@@" != "true" ]; then
rm -rf /var/www/html
cp -r /home/vagrant/html /var/www
fi
SHELL
box.vm.provision "shell", run: "always", inline: <<-SHELL
if [ "@@MOCHA_ALWAYS_PROVISION@@" == "true" ]; then
rm -rf /var/www/html
cp -r /home/vagrant/html /var/www
rm -rf /etc/mocha/*
echo "!! WARNING !! This is a TRANSIENT SUV !!"
echo ">> Data you change on this instance WILL NOT BE SAVED"
echo ">> You MUST migrate your changes manually before shutting down if you wish to save them"
else
echo "!! This is a PERSISTENT SUV !!"
echo ">> Data you change on this instance will be kept INDEFINITELY"
echo ">> UNTIL you manually reset it with 'mocha suv reset'"
fi
chown --recursive webmaster /var/www
chgrp --recursive webmasters /var/www
chmod a+x /etc/mocha
# record the initial start time for the SUV
echo $(date "+%Y-%m-%dT%H:%M:%S") > /etc/mocha/suvstart
chmod a+r /etc/mocha/suvstart
# create the initial mocha user and get a randomly generated password
mocha up
SHELL
end
config.trigger.after :up do |trigger|
trigger.info = "Open newly provisioned SUV in firefox"
trigger.run = {inline: "bash -c 'firefox https://@@MOCHA_SUV_HOSTNAME@@/super/d/home.htmld' &"}
end
end

View File

@ -0,0 +1 @@
/home/beckermj/Documents/Projects/mocha/common/admin/certs/localhost.crt

View File

@ -0,0 +1 @@
/home/beckermj/Documents/Projects/mocha/common/admin/certs/localhost.key

View File

@ -0,0 +1 @@
/home/beckermj/Documents/Projects/mocha/common/admin/mocha-libexec

View File

@ -0,0 +1 @@
/home/beckermj/Documents/Projects/mocha/php/mocha-ccx

View File

@ -0,0 +1,37 @@
<VirtualHost *:443>
# The ServerName directive sets the request scheme, hostname and port that
# the server uses to identify itself. This is used when creating
# redirection URLs. In the context of virtual hosts, the ServerName
# specifies what hostname must appear in the request's Host: header to
# match this virtual host. For the default virtual host (this file) this
# value is not decisive as it is used as a last resort host regardless.
# However, you must set it for any further virtual host explicitly.
#ServerName www.example.com
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
<Directory /var/www/>
AllowOverride All
</Directory>
SSLEngine on
SSLCertificateFile /etc/ssl/certs/localhost.crt
SSLCertificateKeyFile /etc/ssl/certs/localhost.key
# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# For most configuration files from conf-available/, which are
# enabled or disabled at a global level, it is possible to
# include a line for only one particular virtual host. For example the
# following line enables the CGI configuration for this host only
# after it has been globally disabled with "a2disconf".
#Include conf-available/serve-cgi-bin.conf
</VirtualHost>

View File

@ -0,0 +1 @@
/home/beckermj/Documents/Projects/mocha/sql

View File

@ -0,0 +1,215 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
# The most common configuration options are documented and commented below.
# For a complete reference, please see the online documentation at
# https://docs.vagrantup.com.
config.vm.define "@@MOCHA_SUV_ID@@" do |box|
# Every Vagrant development environment requires a box. You can search for
# boxes at https://vagrantcloud.com/search.
# box.vm.box = "mocha/lunar64"
box.vm.box = "ubuntu/lunar64"
#box.vm.box = "default.box"
box.vm.hostname = "@@MOCHA_SUV_ID@@.privatesuv.com"
# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs
# `vagrant box outdated`. This is not recommended.
# box.vm.box_check_update = false
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
# NOTE: This will enable public access to the opened port
# box.vm.network "forwarded_port", guest: 80, host: 8080
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine and only allow access
# via 127.0.0.1 to disable public access
# box.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
# Create a private network, which allows host-only access to the machine
# using a specific IP.
#box.vm.network "private_network", type: "dhcp"
box.vm.network "private_network", ip: "@@MOCHA_SUV_ADDRESS@@"
# Create a public network, which generally matched to bridged network.
# Bridged networks make the machine appear as another physical device on
# your network.
# box.vm.network "public_network"
# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
# box.vm.synced_folder "../data", "/vagrant_data"
# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose provider-specific options.
# Example for VirtualBox:
#
# box.vm.provider "virtualbox" do |vb|
# # Display the VirtualBox GUI when booting the machine
# vb.gui = true
#
# # Customize the amount of memory on the VM:
# vb.memory = "1024"
# end
#
# View the documentation for the provider you are using for more
# information on available options.
box.vm.provider "virtualbox" do |vb|
vb.name = "mochasuv-@@MOCHA_SUV_ID@@"
end
# Enable provisioning with a shell script. Additional provisioners such as
# Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
# documentation for more information about their specific syntax and use.
box.vm.provision "shell", inline: <<-SHELL
# create peristent mocha configuration dir
mkdir /etc/mocha
echo "pending:building:1/27:check for updates" > /etc/mocha/suvstatus
apt-get update
echo "pending:building:2/27:install dependencies" > /etc/mocha/suvstatus
apt-get install -y mariadb-server apache2 php php-mysql php-xml php-mbstring pwgen
echo "pending:building:3/27:apply web server configuration" > /etc/mocha/suvstatus
# enable apache modules
a2enmod rewrite
a2enmod ssl
systemctl restart apache2
# ssh - for development only - REMOVE if publishing for public use
sed -e "s/KbdInteractiveAuthentication no/KbdInteractiveAuthentication yes/" /etc/ssh/sshd_config > /etc/ssh/sshd_config
systemctl restart ssh
echo "pending:building:4/27:configure users" > /etc/mocha/suvstatus
# add webmasters group and webmaster user
addgroup webmasters
WEBMASTER_PASS="Solty/AyanamiREI^^96274"
useradd -G webmasters -p "$(openssl passwd -6 $WEBMASTER_PASS)" webmaster
echo "pending:building:5/27:import machine template" > /etc/mocha/suvstatus
SHELL
box.vm.provision "file", source: "site.conf", destination: "$HOME/mochadev.conf"
box.vm.provision "file", source: "localhost.key", destination: "$HOME/localhost.key"
box.vm.provision "file", source: "localhost.crt", destination: "$HOME/localhost.crt"
box.vm.provision "file", source: "mocha-libexec", destination: "$HOME/mocha-libexec"
box.vm.provision "file", source: "sql", destination: "$HOME/sql"
# initial provision of site
box.vm.provision "shell", inline: <<-SHELL
# **************************************************************
# SITE CONFIGURATION AND SSL
# **************************************************************
mv /home/vagrant/mochadev.conf /etc/apache2/sites-available/mochadev.conf
mv /home/vagrant/localhost.key /etc/ssl/certs
mv /home/vagrant/localhost.crt /etc/ssl/certs
# **************************************************************
# APACHE2 CONFIGURATION
# **************************************************************
echo "pending:building:6/27:apply machine template" > /etc/mocha/suvstatus
# block port 80
sed -i -e "s/Listen 80/#Listen 80/" /etc/apache2/ports.conf
# disable default site and enable mochadev site
a2dissite 000-default
a2ensite mochadev
# reload configuration
systemctl reload apache2
echo "pending:building:7/27:install utilities" > /etc/mocha/suvstatus
mkdir /usr/lib/mocha
echo "mocha_suv" > /etc/mocha/dbname
echo "mocha_suv" > /etc/mocha/dbuser
mv /home/vagrant/mocha-libexec/mocha /usr/bin/mocha
mv /home/vagrant/mocha-libexec/mocha-* /usr/lib/mocha
mv /home/vagrant/mocha-libexec/internal /usr/lib/mocha
mv /home/vagrant/mocha-libexec/spot_register_for_shutdown /usr/lib/mocha
mv /home/vagrant/sql /usr/lib/mocha/sql
chmod a+x /usr/bin/mocha
chmod --recursive a+x /usr/lib/mocha
echo "pending:building:8/27:reset suv" > /etc/mocha/suvstatus
SHELL
# reset the site to the default upon launching the VM
# remove the run: "always" if you do not desire this behavior
box.vm.provision "file", source: "site", destination: "$HOME/html"
box.vm.provision "file", source: "site/.htaccess", destination: "$HOME/html/.htaccess"
box.vm.provision "shell", inline: <<-SHELL
if [ "@@MOCHA_ALWAYS_PROVISION@@" != "true" ]; then
rm -rf /var/www/html
cp -r /home/vagrant/html /var/www
fi
SHELL
box.vm.provision "shell", run: "always", inline: <<-SHELL
if [ "@@MOCHA_ALWAYS_PROVISION@@" == "true" ]; then
rm -rf /var/www/html
cp -r /home/vagrant/html /var/www
rm -rf /etc/mocha/*
echo "!! WARNING !! This is a TRANSIENT SUV !!"
echo ">> Data you change on this instance WILL NOT BE SAVED"
echo ">> You MUST migrate your changes manually before shutting down if you wish to save them"
else
echo "!! This is a PERSISTENT SUV !!"
echo ">> Data you change on this instance will be kept INDEFINITELY"
echo ">> UNTIL you manually reset it with 'mocha suv reset'"
fi
chown --recursive webmaster /var/www
chgrp --recursive webmasters /var/www
chmod a+x /etc/mocha
# record the initial start time for the SUV
echo $(date "+%Y-%m-%dT%H:%M:%S") > /etc/mocha/suvstart
chmod a+r /etc/mocha/suvstart
# create the initial mocha user and get a randomly generated password
mocha up
echo "running:buildcompleted" > /etc/mocha/suvstatus
SHELL
end
config.trigger.after :up do |trigger|
trigger.info = "Open newly provisioned SUV in firefox"
trigger.run = {inline: "bash -c 'firefox https://@@MOCHA_SUV_HOSTNAME@@/super/d/home.htmld' &"}
end
end

View File

@ -0,0 +1 @@
/home/beckermj/Documents/Projects/mocha/common/admin/certs/localhost.crt

View File

@ -0,0 +1 @@
/home/beckermj/Documents/Projects/mocha/common/admin/certs/localhost.key

View File

@ -0,0 +1 @@
/home/beckermj/Documents/Projects/mocha/common/admin/mocha-libexec

View File

@ -0,0 +1 @@
/home/beckermj/Documents/Projects/mocha/php/mocha

View File

@ -0,0 +1,37 @@
<VirtualHost *:443>
# The ServerName directive sets the request scheme, hostname and port that
# the server uses to identify itself. This is used when creating
# redirection URLs. In the context of virtual hosts, the ServerName
# specifies what hostname must appear in the request's Host: header to
# match this virtual host. For the default virtual host (this file) this
# value is not decisive as it is used as a last resort host regardless.
# However, you must set it for any further virtual host explicitly.
#ServerName www.example.com
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
<Directory /var/www/>
AllowOverride All
</Directory>
SSLEngine on
SSLCertificateFile /etc/ssl/certs/localhost.crt
SSLCertificateKeyFile /etc/ssl/certs/localhost.key
# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# For most configuration files from conf-available/, which are
# enabled or disabled at a global level, it is possible to
# include a line for only one particular virtual host. For example the
# following line enables the CGI configuration for this host only
# after it has been globally disabled with "a2disconf".
#Include conf-available/serve-cgi-bin.conf
</VirtualHost>

View File

@ -0,0 +1 @@
/home/beckermj/Documents/Projects/mocha/sql

View File

@ -0,0 +1,68 @@
--- # YAML definition for 1$1, Class
instances:
- inst: &IDA_Name
- inst: &IDC_Class # defines anchor label &id001
class: *IDC_Class
name: Class
index: 1
attributes:
- *IDA_Name
- inst: &IDC_Attribute
class: *IDC_Class
name: Attribute
index: 2
abstract: true
- inst: &IDC_Relationship
class: *IDC_Class
name: Relationship
index: 3
- inst: &IDC_TextAttribute
class: *IDC_Class
inherits: *IDC_Attribute
index: 4
- inst: &IDA_Name
class: *IDC_TextAttribute
# Relationships
- inst: &IDR_Class__has__Attribute
class: *IDC_Relationship
parms:
sourceClass: *IDC_Class
type: has
destinationClass: *IDC_Attribute
sibling: *IDR_Attribute__for__Class
singular: false
- inst: &IDR_Attribute__for__Class
class: *IDC_Relationship
parms:
sourceClass: *IDC_Attribute
type: for
destinationClass: *IDC_Class
sibling: *IDR_Class__has__Attribute
singular: false
- inst: &IDR_Class__has__Relationship
class: *IDC_Relationship
parms:
sourceClass: *IDC_Class
type: has
destinationClass: *IDC_Relationship
sibling: *IDR_Relationship__for__Class
singular: false
- inst: &IDR_Relationship__for__Class
class: *IDC_Relationship
parms:
sourceClass: *IDC_Relationship
type: for
destinationClass: *IDC_Class
sibling: *IDR_Class__has__Relationship
singular: false
...

View File

@ -0,0 +1,89 @@
---
# YAML definition for Boolean Attribute
instances:
- inst: &IDC_BooleanAttribute
class: *IDC_Class
name: Boolean Attribute
index: 5
# YAML definition for Instances of Boolean Attribute, 1$5
- inst: &IDA_Singular
class: *IDC_BooleanAttribute
name: Singular
index: 1
- inst: &IDA_Abstract
class: *IDC_BooleanAttribute
name: Abstract
index: 2
- inst: &IDA_Static
class: *IDC_BooleanAttribute
name: Static
index: 3
- inst: &IDA_Set
class: *IDC_BooleanAttribute
name: Set
index: 4
- inst: &IDA_Build
class: *IDC_BooleanAttribute
name: Build
index: 5
- inst: &IDA_True
class: *IDC_BooleanAttribute
name: "True"
index: 6
- inst: &IDA_ThisInstanceEqualToInstanceParm
class: *IDC_BooleanAttribute
name: This instance equal to Instance Parm
index: 7
- inst: &IDA_AllowNegative
class: *IDC_BooleanAttribute
name: Allow Negative
index: 8
- inst: &IDA_StaticOnly
class: *IDC_BooleanAttribute
name: Static Only
index: 9
- inst: &IDA_AddReferences
class: *IDC_BooleanAttribute
name: Add References
index: 10
- inst: &IDA_RemoveExecutionMetricsConfiguration
class: *IDC_BooleanAttribute
name: Remove Execution Metrics Configuration
index: 12
- inst: &IDA_PassAllParms
class: *IDC_BooleanAttribute
name: Pass All Parms
index: 13
- inst: &IDA_DoNotUseMBResultSave
class: *IDC_BooleanAttribute
name: Do Not Use MB Result Save
index: 14
- inst: &IDA_BuiltFromBEMProcessNotInListForElement
class: *IDC_BooleanAttribute
name: Built from BEM Process that is not in list for Element
index: 15
- inst: &IDA_MultipleValidClasses
class: *IDC_BooleanAttribute
name: Multiple Valid Classes
index: 16
- inst: &IDA_Shared
class: *IDC_BooleanAttribute
name: Shared
index: 17
- inst: &IDA_UseAnyCondition
class: *IDC_BooleanAttribute
name: Use Any Condition
index: 18
- inst: &IDA_IncludeMIs
class: *IDC_BooleanAttribute
name: Include MIs
index: 20
- inst: &IDA_IncludeSuperclassMethods
class: *IDC_BooleanAttribute
name: Include Superclass Methods
index: 21
- inst: &IDA_AllowAny
class: *IDC_BooleanAttribute
name: Allow Any
index: 22

View File

@ -0,0 +1,13 @@
---
# YAML definition for Element, 1$6
instances:
- inst: &IDC_Element
class: *IDC_Class
name: Element
index: 6
- inst: &IDI_Element_AddMetadataInstance
class: *IDC_Element
name: add metadata instance
index: 1

View File

@ -0,0 +1,6 @@
<html>
<head>
<title> Workday Student Grid View Test</title>
</head>
<body>
<div

16
php/mocha-ccx/.htaccess Normal file
View File

@ -0,0 +1,16 @@
RewriteEngine On
# Do not remove this line, otherwise mod_rewrite rules will stop working
# RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
#RewriteRule ^Themes\/(.*)\/Theme\.css$ lessc.php?filename=themes/$1/main [PT,L,QSA]
RewriteRule ^themes\/(.*)\/theme\.css$ lessc.php?filename=themes/$1/main [PT,L,QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?virtualpath=$1 [PT,L,QSA]
#RewriteRule ^StyleSheets\/(.*)\.css$ lessc.php?filename=$1 [PT,L,QSA]

39
php/mocha-ccx/index.php Normal file
View File

@ -0,0 +1,39 @@
<?php
// =============================================================================
// Phast bootstrapper - loads the application modules and executes Phast
// Copyright (C) 2013-2014 Mike Becker
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// =============================================================================
// Load the Phast content (which also include_once's the system modules and
// other Phast-specific stuff)
require_once("lib/phast/System.inc.php");
// Bring in the Phast\System and Phast\IncludeFile classes so we can simply refer
// to them (in this file only) as "System" and "IncludeFile", respectively, from
// now on
use Phast\System;
use Phast\IncludeFile;
// We need to set the root path of the Web site. It's usually something like
// /var/www/yourdomain.com.
System::SetApplicationPath(dirname(__FILE__));
// Tell Phast that we are ready to launch the application. This searches the entire
// directory hierarchy for Phast files, loading *.phpx files as Phast XML files and
// *.phpx.php files as PHP code-behind files. We may decide to use the *.ctlx extension
// (and its associated *.ctlx.php) for PHPX controls.
System::Launch();
?>

36
php/mocha-ccx/lessc.php Normal file
View File

@ -0,0 +1,36 @@
<?php
require_once ("lib/phast/Compilers/StyleSheet/Internal/LessStyleSheetCompiler.inc.php");
require_once ("lib/phast/Compilers/StyleSheet/Internal/Formatters/CompressedFormatter.inc.php");
use Phast\Compilers\StyleSheet\Internal\LessStyleSheetCompiler;
use Phast\Compilers\StyleSheet\Internal\Formatters\CompressedFormatter;
header("Content-Type: text/css");
$filename = $_GET["filename"];
if ((isset($_GET["compile"]) && $_GET["compile"] == "false") || file_exists($filename . ".css"))
{
readfile($filename . ".css");
}
else
{
try
{
#echo ("/* " . $filename . ".less" . " */");
$less = new LessStyleSheetCompiler();
$less->formatter = new CompressedFormatter();
$v = $less->compileFile($filename . ".less");
echo("/* compiled with lessphp v0.4.0 - GPLv3/MIT - http://leafo.net/lessphp */\n");
echo("/* for human-readable source of this file, replace .css with .less in the file name */\n");
echo($v);
}
catch (Exception $e)
{
echo "/* " . $e->getMessage() . " */\n";
}
}
?>

1
php/mocha-ccx/lib/phast Symbolic link
View File

@ -0,0 +1 @@
/home/beckermj/Documents/Projects/phast/app/lib/phast

View File

@ -0,0 +1,17 @@
<Website>
<MasterPages>
<MasterPage FileName="masterPages/Blank.phpx" CodeBehindClassName="Mocha\UI\MasterPages\BlankMasterPage">
<Scripts>
<Script ContentType="text/javascript" FileName="~/scripts/spot_timer.js" />
</Scripts>
<References>
<Reference TagPrefix="html" NamespacePath="Phast\HTMLControls" />
<Reference TagPrefix="wcx" NamespacePath="Phast\WebControls" />
</References>
<Content>
<wcx:SectionPlaceholder ID="aspcContent">
</wcx:SectionPlaceholder>
</Content>
</MasterPage>
</MasterPages>
</Website>

View File

@ -0,0 +1,30 @@
<?php
namespace Mocha\UI\MasterPages;
use Phast\RenderedEventArgs;
use Phast\RenderingEventArgs;
use Phast\RenderMode;
use Phast\System;
use Phast\WebPage;
class BlankMasterPage extends WebPage
{
protected function OnRendering(RenderingEventArgs $re)
{
if ($re->RenderMode === RenderMode::Complete)
{
echo("<!DOCTYPE html>");
echo("<html xmlns=\"http:http://www.w3.org/1999/xhtml\">");
}
}
protected function OnRendered(RenderedEventArgs $e)
{
if ($e->RenderMode === RenderMode::Complete)
{
echo("</html>");
}
}
}
?>

View File

@ -0,0 +1,18 @@
<?php
namespace Mocha\UI\Pages;
use Phast\RenderingEventArgs;
use Phast\WebPage;
class HomePage extends WebPage
{
protected function OnRendering(RenderingEventArgs $re)
{
parent::OnRendering($re);
mocha_init_spot_timer($this);
}
}
?>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Website>
<Pages>
<Page MasterPageFileName="masterPages/Blank.phpx" FileName="ccx/service/{tenant}/{servicename}/{version}" CodeBehindClassName="Mocha\UI\Pages\CcxPage" />
</Pages>
</Website>

34
php/mocha-ccx/xmltest.php Normal file
View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<head>
<title>XML test</title>
</head>
<body>
<form method="POST" enctype="multipart/form-data">
<label for="file1">File: </label><input id="file1" name="file1" type="file" />
<input type="submit" value="Upload" />
</form>
<?php
if ($_SERVER["REQUEST_METHOD"] === "POST")
{
$file1 = $_FILES["file1"];
if ($file1["error"] === UPLOAD_ERR_OK)
{
if ($file1["size"] > 100000)
{
die();
}
$yaml = \yaml_parse(file_get_contents($file1["tmp_name"]));
print_r($yaml);
}
else{
print_r($file1);
}
}
?>
</body>
</html>

16
php/mocha/.htaccess Normal file
View File

@ -0,0 +1,16 @@
RewriteEngine On
# Do not remove this line, otherwise mod_rewrite rules will stop working
# RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
#RewriteRule ^Themes\/(.*)\/Theme\.css$ lessc.php?filename=themes/$1/main [PT,L,QSA]
RewriteRule ^themes\/(.*)\/theme\.css$ lessc.php?filename=themes/$1/main [PT,L,QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?virtualpath=$1 [PT,L,QSA]
#RewriteRule ^StyleSheets\/(.*)\.css$ lessc.php?filename=$1 [PT,L,QSA]

View File

@ -1,3 +0,0 @@
<?php
?>

View File

@ -1,8 +0,0 @@
<?php
namespace Mocha\Core;
class DatabaseOms
{
}
?>

46
php/mocha/images/suv.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,168 @@
<?php
use Mocha\Oms\MySQLDatabaseOms;
use Phast\System;
function mocha_get_oms()
{
global $oms;
if ($oms === null)
{
$oms = new MySQLDatabaseOms(System::GetConfigurationValue("Database.ServerName"), System::GetConfigurationValue("Database.PortNumber"), System::GetConfigurationValue("Database.DatabaseName"), System::GetConfigurationValue("Database.UserName"), System::GetConfigurationValue("Database.Password"));
}
return $oms;
}
function mocha_init_spot_timer($pg)
{
$literalSpotTimer = $pg->GetControlByID("literalSpotTimer");
if (file_exists("/etc/mocha/suvstart"))
{
$suv_start_time = trim(file_get_contents("/etc/mocha/suvstart"));
$suv_start_time_d = new \DateTime($suv_start_time);
$suv_start_time_d->setTimezone(new \DateTimeZone("UTC"));
// this can be adjusted?
$suv_end_time_d = $suv_start_time_d->add(new \DateInterval("PT10H"));
$suv_end_time_d->setTimezone(new \DateTimeZone("UTC"));
$suv_end_time = $suv_end_time_d->format('Y-m-d\TH:i:s\Z');
$suv_current_time_d = new \DateTime();
$interval = $suv_end_time_d->diff($suv_current_time_d);
$literalSpotTimer->Content = $interval->h . ":" . $interval->i;
$spotTimerInitializationScript = $pg->Page->GetControlByID("spotTimerInitializationScript");
$spotTimerInitializationScript->Content = <<<EOT
<script type="text/javascript">
var spot_end_time = new Date('$suv_end_time');
window.datediff = function(earlierDate, laterDate)
{
var interval = { };
var a = earlierDate, b = laterDate;
console.log(earlierDate);
console.log(laterDate);
const _MS_PER_DAY = 1000 * 60 * 60 * 24;
// Discard the time and time-zone information.
const utc1 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate(), a.getHours(), a.getMinutes(), a.getSeconds());
const utc2 = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate(), b.getHours(), b.getMinutes(), b.getSeconds());
console.log(utc2);
console.log(utc1);
var diffMS = (utc2 - utc1);
console.log(diffMS);
var secs = (diffMS / 1000) % 60;
var mins = (diffMS / (1000 * 60)) % 60;
var hrs = (diffMS / (1000 * 60 * 60)) % 24;
interval =
{
"raw": diffMS,
"seconds": Math.floor(secs),
"minutes": Math.floor(mins),
"hours": Math.floor(hrs)
};
return interval;
};
window.spot_timer_tick = function()
{
var spot_cur_time = new Date();
var diff = datediff(spot_cur_time, spot_end_time);
console.log(diff);
document.getElementById('spot_timer').innerHTML = diff.hours + ':' + diff.minutes.toString().padStart(2, '0');
window.setTimeout(spot_timer_tick, 60000);
};
window.addEventListener("load", function()
{
spot_timer_tick();
});
</script>
EOT;
}
}
System::$BeforeGetTenantNameHandler = function()
{
$path = System::GetVirtualPath(false);
if ($path[0] === "madi")
{
return $path[2];
}
return $path[0];
};
System::$BeforeLaunchEventHandler = function($path)
{
/**
* @var MySQLDatabaseOms
*/
/**
* @var MySQLDatabaseOms
*/
$oms = mocha_get_oms();
if (count($path) >= 1 && $path[0] == "suv")
{
if (count($path) == 2 && ($path[1] == "suvinfo.html" || $path[1] == "phpinfo.html"))
{
//
return true;
}
else
{
header("HTTP/1.1 404 Not Found");
echo ("Not Found");
return false;
}
}
if (count($path) == 0)
{
System::Redirect("~/" . System::$Configuration["Application.DefaultTenant"], true);
return false;
}
if (count($path) == 1)
{
System::Redirect("~/" . $path[0] . "/d/home.htmld", true);
return false;
}
if (!isset($_SESSION["user_token"]))
{
if (count($path) >= 4)
{
if ($path[0] == "madi" && $path[1] == "authgwy")
{
$_SESSION["CurrentTenantName"] = $path[2];
$tenant = $oms->getTenantByName($_SESSION["CurrentTenantName"]);
if ($tenant == null)
{
}
return true;
}
}
else
{
// FIXME
if ($path[0] != "themes")
{
$_SESSION["CurrentTenantName"] = $path[0];
}
}
$_SESSION["login_return"] = $path;
System::RedirectToLoginPage(true);
return false;
}
return true;
};
?>

View File

@ -0,0 +1,28 @@
<?php
use Phast\IncludeFile;
use Phast\System;
System::$IncludeFiles[] = new IncludeFile("/lib/mocha/system.inc.php", true);
System::$EnableTenantedHosting = false;
System::$Configuration["Application.Title"] = "Mocha SUV";
System::$Configuration["Application.DefaultTenant"] = "super";
System::$Configuration["Application.ThemeName"] = "clearview";
System::$Configuration["Database.ServerName"] = "localhost";
System::$Configuration["Database.PortNumber"] = 3306;
System::$Configuration["Database.DatabaseName"] = "@@MOCHA_DB_DATABASENAME@@";
System::$Configuration["Database.UserName"] = "@@MOCHA_DB_USERNAME@@";
System::$Configuration["Database.Password"] = "@@MOCHA_DB_PASSWORD@@";
System::$Configuration["LoginPageRedirectURL"] = "~/madi/authgwy/$(CurrentTenantName)/login.htmld";
System::$Configuration["Runtime.DisableAutomaticExtensionParsing"] = true;
System::$Configuration["Paths.MasterPages"] = [ "/ui/masterPages" ];
System::$Configuration["Paths.Pages"] = [ "/ui/pages" ];
require_once ("BeforeLaunchEvent.inc.php");
?>

39
php/mocha/index.php Normal file
View File

@ -0,0 +1,39 @@
<?php
// =============================================================================
// Phast bootstrapper - loads the application modules and executes Phast
// Copyright (C) 2013-2014 Mike Becker
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// =============================================================================
// Load the Phast content (which also include_once's the system modules and
// other Phast-specific stuff)
require_once("lib/phast/System.inc.php");
// Bring in the Phast\System and Phast\IncludeFile classes so we can simply refer
// to them (in this file only) as "System" and "IncludeFile", respectively, from
// now on
use Phast\System;
use Phast\IncludeFile;
// We need to set the root path of the Web site. It's usually something like
// /var/www/yourdomain.com.
System::SetApplicationPath(dirname(__FILE__));
// Tell Phast that we are ready to launch the application. This searches the entire
// directory hierarchy for Phast files, loading *.phpx files as Phast XML files and
// *.phpx.php files as PHP code-behind files. We may decide to use the *.ctlx extension
// (and its associated *.ctlx.php) for PHPX controls.
System::Launch();
?>

36
php/mocha/lessc.php Normal file
View File

@ -0,0 +1,36 @@
<?php
require_once ("lib/phast/Compilers/StyleSheet/Internal/LessStyleSheetCompiler.inc.php");
require_once ("lib/phast/Compilers/StyleSheet/Internal/Formatters/CompressedFormatter.inc.php");
use Phast\Compilers\StyleSheet\Internal\LessStyleSheetCompiler;
use Phast\Compilers\StyleSheet\Internal\Formatters\CompressedFormatter;
header("Content-Type: text/css");
$filename = $_GET["filename"];
if ((isset($_GET["compile"]) && $_GET["compile"] == "false") || file_exists($filename . ".css"))
{
readfile($filename . ".css");
}
else
{
try
{
#echo ("/* " . $filename . ".less" . " */");
$less = new LessStyleSheetCompiler();
$less->formatter = new CompressedFormatter();
$v = $less->compileFile($filename . ".less");
echo("/* compiled with lessphp v0.4.0 - GPLv3/MIT - http://leafo.net/lessphp */\n");
echo("/* for human-readable source of this file, replace .css with .less in the file name */\n");
echo($v);
}
catch (Exception $e)
{
echo "/* " . $e->getMessage() . " */\n";
}
}
?>

View File

@ -0,0 +1,17 @@
<?php
namespace Mocha\Core;
class TenantReference
{
public $ID;
public $Name;
public $GlobalIdentifier;
public function __construct($id, $name, $globalIdentifier)
{
$this->ID = $id;
$this->Name = $name;
$this->GlobalIdentifier = $globalIdentifier;
}
}
?>

View File

@ -0,0 +1,311 @@
<?php
namespace Mocha\Oms;
use Mocha\Core\InstanceKey;
use Mocha\Core\InstanceReference;
use Mocha\Core\TenantReference;
class MySQLDatabaseOms extends DatabaseOms
{
private \PDO $PDO;
/**
* Gets the tenant with the specified name, or NULl if no tenant with the specified name exists on the server.
*
* @param string $tenantName the name of the desired tenant
*
* @return ?TenantReference
*/
public function getTenantByName(string $tenantName) : ?TenantReference
{
$query = "SELECT * FROM mocha_tenants WHERE tenant_name = :tenant_name;";
$stmt = $this->PDO->prepare($query);
$result = $stmt->execute(array
(
"tenant_name" => $tenantName
));
$values = $stmt->fetch();
if ($values !== false)
{
$tenant = new TenantReference($values["id"], $values["tenant_name"], $values["global_identifier"]);
return $tenant;
}
return null;
}
public function __construct($hostname, $port, $databasename, $username, $password)
{
$this->PDO = new \PDO("mysql:host=" . $hostname . ";port=" . $port . ";dbname=" . $databasename, $username, $password);
}
public function getDbId($instRef)
{
if ($instRef == null)
return 0;
return $instRef->DatabaseId;
}
public function createInstanceOf(InstanceReference $classInstance) : ?InstanceReference
{
$query = "CALL mocha_create_instance_of(:tenant_id, :class_index, :global_identifier, :user_inst_id, :effective_date);";
$stmt = $this->PDO->prepare($query);
$result = $stmt->execute(array
(
"tenant_id" => $this->getTenant()->ID,
"class_index" => $classInstance->InstanceKey->InstanceIndex,
"global_identifier" => null,
"user_inst_id" => null,
"effective_date" => null
));
$values = $stmt->fetch();
$stmt->closeCursor();
if ($values !== false)
{
return $this->getInstanceByDBID($values[0]);
}
return null;
}
public function getUserByUserName(string $username) : ?InstanceReference
{
$query = "SELECT mocha_get_user_by_username(:username);";
$stmt = $this->PDO->prepare($query);
$result = $stmt->execute(array
(
"username" => $username
));
$values = $stmt->fetch();
if ($values[0] == null)
return null;
$ir = new InstanceReference();
$ir->DatabaseId = $values[0];
$ir->GlobalIdentifier = $this->getGlobalIdentifier($ir->DatabaseId);
$ir->InstanceKey = $this->getInstanceKey($ir->DatabaseId);
return $ir;
}
public function getGlobalIdentifier($dbid) : string
{
$query = "SELECT global_identifier FROM mocha_instances WHERE id = :id";
$stmt = $this->PDO->prepare($query);
$result = $stmt->execute(array("id" => $dbid));
$values = $stmt->fetch();
return $values[0];
}
public function getInstanceKey($dbid) : InstanceKey
{
$query = "SELECT class_id, inst_id FROM mocha_instances WHERE id = :id";
$stmt = $this->PDO->prepare($query);
$result = $stmt->execute(array("id" => $dbid));
$values = $stmt->fetch();
return new InstanceKey($values["class_id"], $values["inst_id"]);
}
public function getInstanceByDBID(int $dbid) : ?InstanceReference
{
$tenant = $this->getTenant();
if ($tenant === null)
{
trigger_error("tenant cannot be null", \E_USER_ERROR);
return null;
}
$query = "SELECT * FROM mocha_instances WHERE id = :id";
$stmt = $this->PDO->prepare($query);
$result = $stmt->execute(array
(
"id" => $dbid
));
$values = $stmt->fetch();
$ir = new InstanceReference();
$ir->DatabaseId = $values["id"];
$ir->GlobalIdentifier = $values["global_identifier"];
$ir->InstanceKey = new InstanceKey($values["class_id"], $values["inst_id"]);
return $ir;
}
public function getInstanceByGlobalIdentifier(string $globalIdentifier) : ?InstanceReference
{
$tenant = $this->getTenant();
if ($tenant === null)
{
trigger_error("tenant cannot be null", \E_USER_ERROR);
return null;
}
$query = "CALL mocha_get_instance_by_global_identifier(:tenant_id, :global_identifier)";
$stmt = $this->PDO->prepare($query);
$result = $stmt->execute(array
(
"tenant_id" => $tenant->ID,
"global_identifier" => $globalIdentifier
));
if ($result === false)
return null;
$values = $stmt->fetchAll();
if (count($values) == 0)
return null;
$dbid = $values[0]["id"];
$class_id = $values[0]["class_id"];
$inst_id = $values[0]["inst_id"];
$global_id = $values[0]["global_identifier"];
$ir = new InstanceReference();
$ir->DatabaseId = $dbid;
$ir->GlobalIdentifier = $global_id;
$ir->InstanceKey = new InstanceKey($class_id, $inst_id);
return $ir;
}
public function getRelatedInstances(InstanceReference $sourceInstance, InstanceReference $relationshipInstance, \DateTime $effectiveDate = null) : ?array
{
$dt = null;
if ($effectiveDate !== null)
{
$dt = $effectiveDate->format("Y-m-d");
}
$query = "CALL mocha_get_related_instances(:src_inst_id, :rel_inst_id, :eff_date)";
$stmt = $this->PDO->prepare($query);
$result = $stmt->execute(array
(
"src_inst_id" => $this->getDbId($sourceInstance),
"rel_inst_id" => $this->getDbId($relationshipInstance),
"eff_date" => $dt
));
if ($result === false)
{
return null;
}
$values = $stmt->fetchAll();
if (count($values) >= 0)
{
$ret = array();
foreach ($values as $value)
{
$retval = new InstanceReference();
$retval->DatabaseId = $value["id"];
$retval->InstanceKey = new InstanceKey($value["class_id"], $value["inst_id"]);
$retval->GlobalIdentifier = $value["global_identifier"];
$ret[] = $retval;
}
return $ret;
}
return [];
}
public function getAttributeValue($sourceInstance, $attributeInstance, $defaultValue = null, $effectiveDate = null) : ?string
{
$tenant = $this->getTenant();
if ($tenant === null)
{
trigger_error("tenant cannot be null", \E_USER_ERROR);
return null;
}
$query = "CALL mocha_get_attribute_value(:tenant_id, :src_inst_id, :attr_inst_id, :eff_date)";
$stmt = $this->PDO->prepare($query);
$result = $stmt->execute(array
(
"tenant_id" => $tenant->ID,
"src_inst_id" => $this->getDbId($sourceInstance),
"attr_inst_id" => $this->getDbId($attributeInstance),
"eff_date" => $effectiveDate
));
if ($result === false)
{
return $defaultValue;
}
$values = $stmt->fetchAll();
if (count($values) >= 0)
{
$value = $values[0]["att_value"];
return $value;
}
return $defaultValue;
}
public function setAttributeValue(InstanceReference $sourceInstance, InstanceReference $attributeInstance, mixed $value, ?\DateTime $effectiveDate = null)
{
$tenant = $this->getTenant();
if ($tenant === null)
{
trigger_error("tenant cannot be null", \E_USER_ERROR);
return null;
}
$query = "CALL mocha_set_attribute_value(:tenant_id, :src_inst_id, :attr_inst_id, :attr_value, :user_inst_id, :eff_date)";
$stmt = $this->PDO->prepare($query);
$result = $stmt->execute(array
(
"tenant_id" => $tenant->ID,
"src_inst_id" => $this->getDbId($sourceInstance),
"attr_inst_id" => $this->getDbId($attributeInstance),
"attr_value" => $value,
"user_inst_id" => null,
"eff_date" => $effectiveDate
));
}
public function assignRelationship(InstanceReference $sourceInstance, InstanceReference $relationshipInstance, mixed $targetInstance, ?\DateTime $effectiveDate = null)
{
$tenant = $this->getTenant();
if ($tenant === null)
{
trigger_error("tenant cannot be null", \E_USER_ERROR);
return null;
}
if (is_array($targetInstance))
{
}
else
{
$query = "CALL mocha_assign_relationship(:tenant_id, :src_inst_id, :rel_inst_id, :dest_inst_id, :user_inst_id, :eff_date)";
$stmt = $this->PDO->prepare($query);
$result = $stmt->execute(array
(
"tenant_id" => $tenant->ID,
"src_inst_id" => $this->getDbId($sourceInstance),
"rel_inst_id" => $this->getDbId($relationshipInstance),
"dest_inst_id" => $this->getDbId($targetInstance),
"user_inst_id" => null,
"eff_date" => null
));
}
}
public function getInstanceByAttributes($parms)
{
// FIXME: NOT IMPLEMENTED
//usage:
// getInstanceByAttributes (array ( getInstanceByGlobalIdentifier(NAME_ATTRIBUTE) => "zq-developer" ))
$query = "SELECT * FROM mocha_attributes WHERE ";
foreach ($parms as $key => $value)
{
$query .= "(att_value = :att_value AND att_inst_id = :att_id)";
}
$stmt = $this->PDO->prepare($query);
$result = $stmt->execute(array
(
));
$inst = null;
return $inst;
}
}
?>

View File

@ -7,9 +7,15 @@
use Mocha\Core\KnownClassGuids;
use Mocha\Core\KnownInstanceGuids;
use Mocha\Core\KnownAttributeGuids;
use Mocha\Core\TenantReference;
abstract class Oms
{
public function __construct()
{
$this->_tenant = null;
}
/**
* Gets the instance with the specified global identifier.
*/
@ -43,9 +49,35 @@
return $this->getAttributeValue($inst, $this->getInstanceByGlobalIdentifier(KnownAttributeGuids::Name));
}
public function setTenant($tenantName)
private $_tenant;
public function getTenant()
{
$this->_tenantName = $tenantName;
return $this->_tenant;
}
public function setTenant(TenantReference $tenant)
{
$this->_tenant = $tenant;
}
public function getTenantName() : ?string
{
if ($this->_tenant !== null)
{
return $this->_tenant->Name;
}
return null;
}
/**
* Gets the tenant with the specified name, or NULl if no tenant with the specified name exists on the server.
*
* @param string $tenantName the name of the desired tenant
*
* @return ?TenantReference
*/
public function getTenantByName(string $tenantName) : ?TenantReference
{
return null;
}
}
?>

View File

@ -1,9 +1,8 @@
<?php
require("config.inc.php");
require("core/InstanceKey.inc.php");
require("core/InstanceReference.inc.php");
require("core/InstanceSet.inc.php");
require("core/TenantReference.inc.php");
require("core/KnownClassGuids.inc.php");
require("core/KnownInstanceGuids.inc.php");
@ -23,7 +22,6 @@
if ($oms == null)
{
$oms = new \Mocha\Oms\MySQLDatabaseOms("localhost", 3306, "mocha_0001", "mocha_0001", "4hpVLM4QDEfzwZwS");
$oms->setTenant("default");
}
return $oms;
}

1
php/mocha/lib/phast Symbolic link
View File

@ -0,0 +1 @@
/home/beckermj/Documents/Projects/phast/app/lib/phast

View File

@ -1,115 +0,0 @@
<?php
namespace Mocha\Oms;
use Mocha\Core\InstanceKey;
use Mocha\Core\InstanceReference;
class MySQLDatabaseOms extends DatabaseOms
{
public \PDO $PDO;
public function __construct($hostname, $port, $databasename, $username, $password)
{
$this->PDO = new \PDO("mysql:host=" . $hostname . ";port=" . $port . ";dbname=" . $databasename, $username, $password);
}
public function getDbId($instRef)
{
if ($instRef == null)
return 0;
return $instRef->DatabaseId;
}
public function getInstanceByGlobalIdentifier(string $globalIdentifier) : ?InstanceReference
{
$query = "CALL mocha_get_instance_by_global_identifier(:global_identifier)";
$stmt = $this->PDO->prepare($query);
$result = $stmt->execute(array
(
"global_identifier" => $globalIdentifier
));
if ($result === false)
return null;
$values = $stmt->fetchAll();
if (count($values) == 0)
return null;
$dbid = $values[0]["id"];
$class_id = $values[0]["class_id"];
$inst_id = $values[0]["inst_id"];
$global_id = $values[0]["global_identifier"];
$ir = new InstanceReference();
$ir->DatabaseId = $dbid;
$ir->GlobalIdentifier = $global_id;
$ir->InstanceKey = new InstanceKey($class_id, $inst_id);
return $ir;
}
public function getRelatedInstances(InstanceReference $sourceInstance, InstanceReference $relationshipInstance, \DateTime $effectiveDate = null) : ?array
{
$dt = null;
if ($effectiveDate !== null)
{
$dt = $effectiveDate->format("Y-m-d");
}
$query = "CALL mocha_get_related_instances(:src_inst_id, :rel_inst_id, :eff_date)";
$stmt = $this->PDO->prepare($query);
$result = $stmt->execute(array
(
"src_inst_id" => $this->getDbId($sourceInstance),
"rel_inst_id" => $this->getDbId($relationshipInstance),
"eff_date" => $dt
));
if ($result === false)
{
return null;
}
$values = $stmt->fetchAll();
if (count($values) >= 0)
{
$ret = array();
foreach ($values as $value)
{
$retval = new InstanceReference();
$retval->DatabaseId = $value["id"];
$retval->InstanceKey = new InstanceKey($value["class_id"], $value["inst_id"]);
$retval->GlobalIdentifier = $value["global_identifier"];
$ret[] = $retval;
}
return $ret;
}
return [];
}
public function getAttributeValue($sourceInstance, $attributeInstance, $defaultValue = null, $effectiveDate = null) : ?string
{
$query = "CALL mocha_get_attribute_value(:src_inst_id, :attr_inst_id, :eff_date)";
$stmt = $this->PDO->prepare($query);
$result = $stmt->execute(array
(
"src_inst_id" => $this->getDbId($sourceInstance),
"attr_inst_id" => $this->getDbId($attributeInstance),
"eff_date" => $effectiveDate
));
if ($result === false)
{
return $defaultValue;
}
$values = $stmt->fetchAll();
if (count($values) >= 0)
{
$value = $values[0]["att_value"];
return $value;
}
return $defaultValue;
}
}
?>

View File

View File

@ -0,0 +1,138 @@
@import "uwt-badge.less";
@import "uwt-button.less";
@import "uwt-colors.less";
@import "uwt-checkbox.less";
@import "uwt-formview.less";
@import "uwt-header.less";
@import "uwt-layout.less";
@import "uwt-listbox.less";
@import "uwt-listview.less";
@import "uwt-panel.less";
@import "uwt-textbox.less";
@import "uwt-toolbar.less";
@import "tx.less";
@import "select2.min.less";
@import "uwt-x-select2.less";
@import "mobile/main.less";
@import "../common/fonts/awesome/css/all.min.css";
html
{
margin: 0px;
}
body
{
background-color: #f3f3f4;
color: #676a6c;
display: flex;
flex-direction: column;
font-family: "Source Sans 3";
margin: 0px;
/* overflow: hidden; */
}
body.login-page
{
justify-content: center;
}
img.header-image
{
width: 128px;
}
/*
div.login-container
{
margin-top: 64px;
align-items: flex-start;
width: 640px;
margin-left: auto;
margin-right: auto;
border: solid 1px #1ab394;
}
div.login-container > table.uwt-formview
{
margin-top: 32px;
}
*/
@media (min-width: 1000px)
{
div.login-container
{
width: 800px;
margin-left: auto;
margin-right: auto;
padding-top: 100px;
}
}
h1, h2, h3, h4, h5, h6
{
font-weight: 100;
}
button:focus, input:focus, select:focus
{
outline-style:solid;
outline-color: #1ab394;
}
.uwt-expand
{
flex-grow: 1;
}
div.mocha-ams-spot-popup
{
margin-left: auto;
margin-right: auto;
position: absolute;
opacity: 0.5;
right: 25%;
width: 120px;
text-align: center;
&> h1
{
font-weight: 600;
background-color: #fff;
margin: 0px;
padding: 8px;
display: block;
margin-left: auto;
margin-right: auto;
}
&> h3
{
font-weight: 600;
margin: 0px;
padding: 4px;
display: block;
margin-left: auto;
margin-right: auto;
}
}
a
{
color: #007bff;
text-underline-offset: 4px;
text-decoration: none;
&:hover
{
color: #0056b3;
text-decoration: underline;
}
}
a.uwt-user-menu-button
{
margin-left: auto;
}

View File

@ -0,0 +1,58 @@
@import "uwt-button-container.less";
@import "uwt-formview.less";
@import "uwt-header.less";
@import "uwt-layout.less";
@import "uwt-panel.less";
@import "uwt-x-select2.less";
@media(min-width: 1000px)
{
.uwt-mobile-only
{
display: none;
}
}
@media(max-width: 1000px)
{
.uwt-mobile-hidden
{
display: none;
}
.uwt-mobile-overlay
{
/* like .uwt-mobile-fullscreen, except initially hidden - add .uwt-visible to show */
position: fixed;
left: 0px;
top: 0px;
right: 0px;
bottom: 0px;
transition: all 0.3s;
opacity: 0;
visibility: hidden;
z-index: 200;
}
.uwt-mobile-overlay.uwt-visible
{
opacity: 1;
visibility: visible;
}
.uwt-mobile-fullscreen
{
/* like .uwt-mobile-overlay, except always visible */
position: fixed;
left: 0px;
top: 0px;
right: 0px;
bottom: 0px;
}
div.login-container
{
margin-top: 0px !important;
width: auto !important;
}
}

View File

@ -0,0 +1,6 @@
div.uwt-mobile-only.uwt-button-container
{
position: fixed;
right: 32px;
bottom: 32px;
}

View File

@ -0,0 +1,21 @@
@media(max-width: 1000px)
{
table.uwt-formview
{
width: 100%;
box-sizing: border-box;
}
table.uwt-formview > tbody > tr > td
{
display: block;
}
table.uwt-formview > tbody > tr > td:first-child
{
margin-bottom: 0px;
}
table.uwt-formview > tbody > tr > td > input:not([type=checkbox])
{
width: 100%;
box-sizing: border-box;
}
}

View File

@ -0,0 +1,7 @@
@media (max-width: 1000px)
{
body > div.uwt-header > a > span.uwt-title, body > form > div.uwt-header > a > span.uwt-title, body > div.uwt-header > div > a > span.uwt-title, body > form > div.uwt-header > div > a > span.uwt-title
{
display: none;
}
}

View File

@ -0,0 +1,11 @@
@media(max-width: 1000px)
{
.uwt-layout.uwt-layout-box.uwt-mobile-orientation-horizontal
{
flex-direction: row !important;
}
.uwt-layout.uwt-layout-box.uwt-mobile-orientation-vertical
{
flex-direction: column !important;
}
}

View File

@ -0,0 +1,23 @@
@media(max-width: 1000px)
{
div.uwt-panel > div.uwt-footer
{
position: fixed;
bottom: 0px;
left: 0px;
right: 0px;
/* padding: 32px; */
padding: 0px;
display: flex;
}
div.uwt-panel > div.uwt-footer > .uwt-button
{
flex-grow: 1;
padding: 16px;
}
div.uwt-panel.uwt-mobile-overlay
{
margin: 0px;
}
}

View File

@ -0,0 +1,12 @@
@media(max-width: 1000px)
{
.select2-dropdown
{
position: fixed;
left: 0px;
right: 0px;
bottom: 0px;
top: 0px;
width: auto !important;
}
}

View File

@ -0,0 +1,102 @@
div.tx-wrapper
{
border: solid 1px #aaaaaa;
display: flex;
flex-direction: column;
}
div.tx-toolbar
{
display: flex;
flex-direction: row;
padding: 16px;
background-color: #eee;
}
div.tx-toolbar > a.uwt-button
{
}
@media (min-width: 1000px)
{
div.tx-wrapper
{
width: 80%;
margin-top: 128px;
margin-left: auto;
margin-right: auto;
}
}
div.tx
{
color: #000000;
font-family: monospace;
font-size: 10pt;
padding: 16px;
}
div.tx a
{
color: inherit;
text-decoration: none;
}
div.tx a:hover
{
text-decoration: underline;
}
div.tx a.uwt-button
{
display: inline-block;
min-width: auto;
min-height: auto;
padding: 2px 8px;
border-radius: 4px;
margin: 4px;
color: #676a6c;
text-decoration: none;
}
div.tx span.tx-keyword
{
color: #0000aa;
font-weight: bold;
}
div.tx span.tx-category
{
color: #003366;
font-weight: bold;
}
div.tx .tx-reference
{
color: #000000;
font-weight: bold;
}
div.tx .tx-reference > i
{
opacity: 0;
position: relative;
display: inline-block;
width: 0px;
}
div.tx .tx-reference::before
{
font-family: "FontAwesome";
content: "\f061";
}
div.tx span.tx-class
{
color: #660066;
font-weight: bold;
}
div.tx div.tx-indent
{
padding-left: 24px;
}
div.tx .tx-comment
{
color: #aaaaaa;
}
div.tx .tx-instance
{
color: #006666;
}
div.tx > div:hover
{
background-color: #eeeeee;
}

View File

@ -0,0 +1,17 @@
div.uwt-badge
{
border-radius: 4px;
display: inline-block;
padding: 8px;
}
div.uwt-badge.uwt-color-primary
{
background-color: var(--uwt-color-primary);
color: #fff;
}
div.uwt-badge.uwt-color-purple
{
background-color: var(--uwt-color-purple);
color: #fff;
}

View File

@ -0,0 +1,44 @@
.uwt-button
{
background-color: #fff;
border: solid 1px #d2d2d2;
padding: 6px;
min-width: 80px;
min-height: 24px;
text-decoration: none;
}
.uwt-button.uwt-color-primary
{
background-color: #1ab394;
border-color: #1ab394;
color: #fff;
}
.uwt-button.uwt-color-primary:hover
{
background-color: #18a689;
border: solid 1px #18a689;
}
.uwt-button.uwt-button-round
{
border-radius: 128px;
width: 64px;
height: 64px;
display: inline-block;
padding: 0px;
min-width: auto;
min-height: auto;
box-shadow: 0px 8px 8px rgba(0,0,0,0.2);
}
.uwt-button.uwt-button-round > i.fa
{
font-size: 20px;
padding: 22px;
}
.uwt-button > span.uwt-title
{
margin-left: 8px;
}

View File

@ -0,0 +1,32 @@
div.uwt-checkbox
{
display: inline-block;
width: 22px;
height: 22px;
vertical-align: middle;
border: 2px solid #ddd;
margin-right: 4px;
}
div.uwt-checkbox:hover
{
border: 2px solid var(--uwt-color-primary);
}
div.uwt-checkbox.uwt-checked
{
background-color: var(--uwt-color-primary);
border-color: var(--uwt-color-primary);
}
div.uwt-checkbox.uwt-checked > i.fa
{
transition: all 0.3s;
margin: 4px;
font-weight: bold;
color: #fff;
}
div.uwt-checkbox:not(.uwt-checked) > i.fa
{
visibility: hidden;
opacity: 0;
}

View File

@ -0,0 +1,24 @@
:root
{
--uwt-color-blue: #007bff;
--uwt-color-indigo: #6610f2;
--uwt-color-purple: #6f42c1;
--uwt-color-pink: #e83e8c;
--uwt-color-red: #dc3545;
--uwt-color-orange: #fd7e14;
--uwt-color-yellow: #ffc107;
--uwt-color-green: #28a745;
--uwt-color-teal: #20c997;
--uwt-color-cyan: #17a2b8;
--uwt-color-white: #fff;
--uwt-color-gray: #6c757d;
--uwt-color-gray-dark: #343a40;
--uwt-color-primary: #1ab394; /* #007bff; */
--uwt-color-secondary: #6c757d;
--uwt-color-success: #28a745;
--uwt-color-info: #17a2b8;
--uwt-color-warning: #ffc107;
--uwt-color-danger: #dc3545;
--uwt-color-light: #f8f9fa;
--uwt-color-dark: #343a40
}

View File

@ -0,0 +1,13 @@
table.uwt-formview > tbody > tr > td
{
margin-bottom: 10px;
padding: 6px;
}
table.uwt-formview > tbody > tr > td:first-child
{
font-weight: bold;
}
table.uwt-formview > tbody > tr > td:first-child > label
{
white-space: nowrap;
}

View File

@ -0,0 +1,31 @@
body > div.uwt-header, body > form > div.uwt-header
{
background-color: #3e495f;
}
body > div.uwt-header > *, body > form > div.uwt-header > *
{
color: #fff;
}
body > div.uwt-header > label
{
padding: 16px;
}
body > div.uwt-header > a, body > form > div.uwt-header > a, body > div.uwt-header > div > a, body > form > div.uwt-header > div > a
{
color: #fff;
display: inline-block;
padding: 16px;
text-decoration: none;
}
body > div.uwt-header > a:hover, body > form > div.uwt-header > a:hover, body > div.uwt-header > div > a:hover, body > form > div.uwt-header > div > a:hover
{
background-color: rgba(0,0,0, 0.3);
}
body > div.uwt-header > a.uwt-selected, body > form > div.uwt-header > a.uwt-selected, body > div.uwt-header > div > a.uwt-selected, body > form > div.uwt-header > div > a.uwt-selected
{
background-color: rgba(0,0,0, 0.5);
}
body > div.uwt-header > a > span.uwt-title, body > form > div.uwt-header > a > span.uwt-title, body > div.uwt-header > div > a > span.uwt-title, body > form > div.uwt-header > div > a > span.uwt-title
{
margin-left: 8px;
}

View File

@ -0,0 +1,18 @@
.uwt-layout.uwt-layout-box
{
display: flex;
}
.uwt-layout.uwt-layout-box.uwt-orientation-horizontal
{
flex-direction: row;
}
.uwt-layout.uwt-layout-box.uwt-orientation-vertical
{
flex-direction: column;
}
.uwt-layout.uwt-layout-box > *.uwt-pack-end
{
/* WARNING: this is not tested, and might only work for this one particular case */
margin-left: auto;
}

View File

@ -0,0 +1,26 @@
ul.uwt-listbox
{
background-color: #fff;
border: 1px solid #e7eaec;
padding: 0px;
}
ul.uwt-listbox > li
{
list-style-type: none;
margin: 0px;
padding: 0px;
}
ul.uwt-listbox > li > div.uwt-title
{
font-weight: bold;
}
ul.uwt-listbox > li > div
{
padding: 8px;
}
ul.uwt-listbox > li:hover
{
background-color: rgba(0,0,0,.075);
}

View File

@ -0,0 +1,39 @@
table.uwt-listview
{
background-color: #fff;
border: 1px solid #e7eaec;
border-collapse: collapse;
}
table.uwt-listview td, table.uwt-listview th
{
border: 1px solid #e7eaec;
padding: 6px;
}
table.uwt-listview th
{
font-weight: lighter;
}
table.uwt-listview > tbody > tr:hover > td
{
background-color: rgba(0,0,0,.075);
color: #212529;
}
table.uwt-listview > tbody > tr > th[colspan]
{
background-color: #cee;
}
table.uwt-listview > tbody > tr > td > button,
table.uwt-listview > tbody > tr > td > a.uwt-button,
table.uwt-listview > tbody > tr > td > input[type=submit],
table.uwt-listview > tbody > tr > td > input[type=reset],
table.uwt-listview > tbody > tr > td > input[type=button]
{
display: block;
margin-left: auto;
margin-right: auto;
}
table.uwt-listview > tbody > tr.uwt-placeholder
{
height: 96px;
background-color: #ccc;
}

View File

@ -0,0 +1,20 @@
div.uwt-panel
{
border: 1px solid #e7eaec;
background-color: #fff;
margin: 32px;
}
div.uwt-panel > div.uwt-header,
div.uwt-panel > div.uwt-content,
div.uwt-panel > div.uwt-footer
{
padding: 30px;
}
div.uwt-panel > div.uwt-content
{
flex-grow: 1;
}
div.uwt-panel > div.uwt-footer
{
text-align: right;
}

View File

@ -0,0 +1,4 @@
input[type=text], input[type=password], input[type=search]
{
padding: 8px;
}

View File

@ -0,0 +1,8 @@
div.uwt-toolbar
{
margin-bottom: 16px;
}
div.uwt-toolbar > a.uwt-button
{
display: inline-block;
}

View File

@ -0,0 +1,20 @@
.select2-container--default .select2-selection--single
{
background-color: #fff;
border-color: #e7eaec;
border-radius: 4px;
}
.select2-dropdown
{
border-color: #e7eaec;
box-shadow: 4px 4px 8px rgba(0,0,0,0.3);
}
.select2-container--default .select2-results__option--highlighted.select2-results__option--selectable
{
background-color: #1ab394;
}
.uwt-formview .select2.select2-container
{
width: 100% !important;
}

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More