mirror of
https://codeberg.org/timelimit/timelimit-server.git
synced 2026-08-31 19:03:45 +02:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
769d828d2b | ||
|
|
f152687a37 | ||
|
|
0f9e1c50e6 | ||
|
|
f6cc231202 | ||
|
|
8665e614b5 | ||
|
|
828399ec14 | ||
|
|
21d7fa839f | ||
|
|
24563bdc4a | ||
|
|
964397cfa9 | ||
|
|
99762d5d36 | ||
|
|
4194641d05 |
@@ -1,3 +1,4 @@
|
||||
build
|
||||
node_modules
|
||||
test.db
|
||||
tempdb
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# Server Setup
|
||||
|
||||
There is a shell script for doing a mostly automated installation at <https://codeberg.org/timelimit/timelimit-server/raw/branch/master/docs/guides/timelimit-server-setup.sh>. During a test, it took 10 minutes to do a installation with it.
|
||||
|
||||
**Read the messages which the script shows** - it is recommend to run it on a clean Debian 10 installation because it overwrites some configuration files.
|
||||
|
||||
## Usage
|
||||
|
||||
- download it (using wget or a webbrowser)
|
||||
- make it executable (``chmod +x timelimit-server-setup.sh``)
|
||||
- run it (``sudo ./timelimit-server-setup.sh``)
|
||||
- answer the questions
|
||||
|
||||
## Requirements
|
||||
|
||||
- a **public** IP address **with** a domain name
|
||||
- a reachable port 80 and 443 (which can need a port forwarding at your router)
|
||||
- a Debian 10 installation (or something comparable) which does not contain anything (important)
|
||||
- a mail address for sending automated mails (using SMTP) which should **not** be your primary mail address
|
||||
|
||||
## Created setup
|
||||
|
||||
- timelimit-server (as a systemd service)
|
||||
- postgresql (connected to timelimit-server using a unix socket)
|
||||
- nginx (connected to timelimit-server using a unix socket)
|
||||
- certbot (to get valid certificates)
|
||||
- a few helper commands with the ``timelimit-`` prefix
|
||||
Executable
+538
@@ -0,0 +1,538 @@
|
||||
#! /bin/bash
|
||||
set -e
|
||||
|
||||
# use the test environment
|
||||
# certenv=live
|
||||
# certbotparams="--test-cert"
|
||||
# use the production environment
|
||||
certenv=live
|
||||
certbotparams=""
|
||||
|
||||
if [ "$(id -u)" != 0 ]; then
|
||||
echo "You must run this as root (with sudo)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v dialog &> /dev/null; then
|
||||
apt update && apt install -y dialog
|
||||
fi
|
||||
|
||||
dialog --yesno "This script will setup a timelimit-server installation. It assumes running at a clean Debian installation for this. Doing this will overwrite and delete some files - you have been warned. Do you want to continue?" 8 60
|
||||
|
||||
dialog --yesno "This device must be reachable from the public internet at port 80 and port 443 and you must have a (sub)domain at which this device can be reached. Do you have got both?" 8 60
|
||||
|
||||
dialog --yesno "Do you accept the current Let's Encrypt Subscriber Agreement which can be found at https://letsencrypt.org/repository/?" 8 60
|
||||
|
||||
apt update
|
||||
|
||||
firewall_mode="$(dialog --menu "Do you want to setup a firewall?" 10 60 3 \
|
||||
no "do not setup a firewall" \
|
||||
base "install ufw and allow http and https" \
|
||||
ssh "install ufw and allow http, https and ssh" \
|
||||
3>&1 1>&2 2>&3)"
|
||||
|
||||
if [ "$firewall_mode" != "no" ]; then
|
||||
apt install -y ufw
|
||||
|
||||
ufw --force reset
|
||||
|
||||
ufw default deny incoming
|
||||
ufw allow http
|
||||
ufw allow https
|
||||
|
||||
if [ "$firewall_mode" = "ssh" ]; then
|
||||
ufw limit ssh
|
||||
fi
|
||||
|
||||
ufw enable
|
||||
fi
|
||||
|
||||
apt install -y curl certbot nginx python3-certbot-nginx
|
||||
|
||||
# minimal nginx setup
|
||||
rm /etc/nginx/sites-enabled/default || true # ignore if it is already deleted
|
||||
curl https://ssl-config.mozilla.org/ffdhe2048.txt > /usr/share/mozilla-dhparam
|
||||
cat > /etc/nginx.conf <<"EOF"
|
||||
user www-data;
|
||||
worker_processes auto;
|
||||
pid /run/nginx.pid;
|
||||
include /etc/nginx/modules-enabled/*.conf;
|
||||
|
||||
events {
|
||||
worker_connections 512;
|
||||
}
|
||||
|
||||
http {
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_tickets off;
|
||||
ssl_dhparam /usr/share/mozilla-dhparam;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
|
||||
gzip off;
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
include /etc/nginx/sites-enabled/*;
|
||||
}
|
||||
EOF
|
||||
cat > /etc/nginx/sites-enabled/http-empty <<"EOF"
|
||||
# this ensures that the certificates can be created/renewed
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
server_tokens off;
|
||||
|
||||
return 403;
|
||||
}
|
||||
EOF
|
||||
systemctl reload nginx
|
||||
|
||||
# get data for cert creation
|
||||
domain="$(dialog --inputbox "At which domain is this device reachable?" 10 60 "" 3>&1 1>&2 2>&3)"
|
||||
if [[ ! "$domain" =~ ^([0-9a-zA-Z]|.)+$ ]] || [[ "$domain" =~ ^\.+$ ]]; then
|
||||
echo "This does not look like a valid domain"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mail="`dialog --inputbox "What's your mail address? It will be the default mail address which can sign in at your timelimit server and it will be sent to Let's Encrypt for the certificate creation." 10 60 "" 3>&1 1>&2 2>&3`"
|
||||
|
||||
if [[ ! $mail =~ ^([0-9a-zA-Z]|-|\.)+@([0-9a-zA-Z]|-|\.)+$ ]]; then
|
||||
echo "This is not look like a valid mail address"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# get certificates
|
||||
certbot certonly --nginx $certbotparams -m "$mail" --agree-tos --non-interactive -d "$domain"
|
||||
|
||||
# add nginx site config
|
||||
cat > /etc/nginx/sites-enabled/https-timelimit <<EOF
|
||||
upstream timelimitbackend {
|
||||
server unix:/var/run/timelimit/server max_fails=0;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
|
||||
server_name $domain;
|
||||
server_tokens off;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/$certenv/$domain/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/$certenv/$domain/privkey.pem;
|
||||
|
||||
location / {
|
||||
proxy_pass http://timelimitbackend/;
|
||||
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
proxy_set_header Host \$http_host;
|
||||
proxy_set_header Upgrade \$http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_http_version 1.1;
|
||||
|
||||
client_max_body_size 10m;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
nginx -t
|
||||
systemctl reload nginx
|
||||
|
||||
# install and configure the database
|
||||
apt install -y postgresql-11
|
||||
runuser -u postgres -- createuser timelimitrun
|
||||
runuser -u postgres -- createdb --encoding=utf8 --owner=timelimitrun timelimit
|
||||
echo "listen_addresses = ''" > /etc/postgresql/11/main/conf.d/disable-tcp-listen.conf
|
||||
cat > /etc/postgresql/11/main/pg_hba.conf <<"EOF"
|
||||
# TYPE DATABASE USER ADDRESS METHOD
|
||||
local all postgres peer
|
||||
local timelimit timelimitrun peer
|
||||
EOF
|
||||
systemctl restart postgresql
|
||||
|
||||
# install more dependencies
|
||||
apt install -y pgp git npm jq
|
||||
|
||||
# create a config
|
||||
mkdir --mode=u=rwx,go=rx /etc/timelimit
|
||||
jq --null-input --arg mailWhitelist "$mail" '{mailWhitelist:$mailWhitelist}' > /etc/timelimit/config.json
|
||||
chmod u=rw,go= /etc/timelimit/config.json
|
||||
|
||||
# create timelimit users
|
||||
useradd timelimitrun && useradd timelimitbuild
|
||||
|
||||
# create directoreis
|
||||
mkdir --mode=u=rwx,go=rx /var/lib/timelimit
|
||||
mkdir --mode=u=rwx,go=rx /var/lib/timelimit/build
|
||||
chown timelimitbuild /var/lib/timelimit/build
|
||||
|
||||
# clone the source code
|
||||
runuser -u timelimitbuild -- git clone --mirror https://codeberg.org/timelimit/timelimit-server.git /var/lib/timelimit/build/mirror
|
||||
|
||||
# create helperscript for building the source code and run it
|
||||
cat > /var/lib/timelimit/build/build.sh <<"EOF"
|
||||
#! /bin/bash
|
||||
set -e
|
||||
cd /var/lib/timelimit/build/mirror
|
||||
git remote update
|
||||
|
||||
current_version=""
|
||||
if [ -f /var/lib/timelimit/run/version.txt ]; then
|
||||
current_version="$(cat /var/lib/timelimit/run/version.txt)"
|
||||
fi
|
||||
|
||||
options=()
|
||||
|
||||
for option in $(git tag | grep -E '^2[0-9]{3}-[0-9]{2}-[0-9]{2}$' | sort --reverse); do
|
||||
info=""
|
||||
|
||||
if [ "$option" = "$current_version" ]; then
|
||||
info="(currently installed)"
|
||||
fi
|
||||
|
||||
options+=("$option" "$info")
|
||||
done
|
||||
|
||||
selected_version="$(dialog --menu "Which version do you want to use?" 15 60 10 "${options[@]}" 3>&1 1>&2 2>&3)"
|
||||
|
||||
rm -rf .gnupg
|
||||
curl https://keys.openpgp.org/vks/v1/by-fingerprint/2E5C672DE893055D04F5B7BC36B449FB5364BDC4 | HOME=/var/lib/timelimit/build/mirror gpg --import
|
||||
echo "2E5C672DE893055D04F5B7BC36B449FB5364BDC4:6:" | HOME=/var/lib/timelimit/build/mirror gpg --import-ownertrust
|
||||
err=0
|
||||
HOME=/var/lib/timelimit/build/mirror git verify-tag --raw "$selected_version" 2>&1 | grep -q '\[GNUPG:\] TRUST_ULTIMATE' || err=$?
|
||||
if [[ $err != 0 ]]; then
|
||||
echo "invalid signature"
|
||||
exit
|
||||
fi
|
||||
|
||||
rm -rf /var/lib/timelimit/build/output/
|
||||
mkdir --mode=u=rwx,go=rx /var/lib/timelimit/build/output
|
||||
git --work-tree=/var/lib/timelimit/build/output/ checkout "$selected_version" -- .
|
||||
|
||||
cd /var/lib/timelimit/build/output/
|
||||
mkdir .npmcache
|
||||
export npm_config_cache=/var/lib/timelimit/build/output/.npmcache
|
||||
# retry a few times
|
||||
npm install --no-optional || npm install --no-optional || npm install --no-optional || npm install --no-optional
|
||||
npm run build
|
||||
npm prune --production
|
||||
rm -rf src .npmcache
|
||||
echo "$selected_version" > version.txt
|
||||
EOF
|
||||
chown timelimitbuild /var/lib/timelimit/build/build.sh
|
||||
chmod u+x /var/lib/timelimit/build/build.sh
|
||||
runuser -u timelimitbuild -- /var/lib/timelimit/build/build.sh
|
||||
|
||||
# create helperscript to use the new built version and use it
|
||||
cat > /var/lib/timelimit/copy-new-build.sh <<"EOF"
|
||||
#! /bin/bash
|
||||
set -e
|
||||
if [[ ! -f /var/lib/timelimit/build/output/version.txt ]]; then
|
||||
echo "There is no new build"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -f /var/lib/timelimit/run/version.txt ]]; then
|
||||
NEWVERSION="$(cat /var/lib/timelimit/build/output/version.txt)"
|
||||
OLDVERSION="$(cat /var/lib/timelimit/run/version.txt)"
|
||||
|
||||
if [[ "$OLDVERSION" > "$NEWVERSION" ]]; then
|
||||
echo ""
|
||||
echo "IMPORTANT"
|
||||
echo ""
|
||||
echo "It looks like you're trying to do a downgrade."
|
||||
echo "This is not recommend so it's blocked."
|
||||
echo "You can run 'rm /var/lib/timelimit/run/version.txt' to remove this check temporarily."
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -rf /var/lib/timelimit/run
|
||||
mkdir --mode=u=rwx,go= /var/lib/timelimit/run
|
||||
cp -r /var/lib/timelimit/build/output/* /var/lib/timelimit/run
|
||||
chmod -R u-w,go-rwx /var/lib/timelimit/run
|
||||
chown -R timelimitrun /var/lib/timelimit/run
|
||||
# allow everyone to see the version
|
||||
chmod go+x /var/lib/timelimit/run
|
||||
chmod go+r /var/lib/timelimit/run/version.txt
|
||||
EOF
|
||||
chmod u+x /var/lib/timelimit/copy-new-build.sh
|
||||
/var/lib/timelimit/copy-new-build.sh
|
||||
|
||||
# create a helperscript to create a env file and use it
|
||||
cat > /var/lib/timelimit/build-env.sh <<"EOF"
|
||||
#! /bin/bash
|
||||
set -e
|
||||
umask 077
|
||||
config="$(cat /etc/timelimit/config.json)"
|
||||
mail_whitelist="$(jq --argjson config "$config" --null-input --raw-output '$config.mailWhitelist | if type == "string" then . else "" end')"
|
||||
disable_signup="$(jq --argjson config "$config" --null-input --raw-output '$config.disableSignup | if type == "boolean" and . == true then "yes" else "no" end')"
|
||||
mail_sender="$(jq --argjson config "$config" --null-input --raw-output '$config.mailTransport.sender | if type == "string" then . else "" end')"
|
||||
mail_transport="$(jq --compact-output --argjson config "$config" --null-input --raw-output '$config.mailTransport | if type == "object" then { host, port, secure, auth: { user, pass } } else null end')"
|
||||
mail_imprint="$(jq --argjson config "$config" --null-input --raw-output '$config.mailImprint | if type == "string" then . else "" end')"
|
||||
encode() {
|
||||
jq --null-input --raw-output --arg data "$1" '$data | gsub("\\\\"; "\\\\") | gsub("\n"; "\\n")'
|
||||
}
|
||||
(
|
||||
[[ "$mail_whitelist" != "" ]] && echo "MAIL_WHITELIST=$(encode "$mail_whitelist")"
|
||||
[[ "$mail_sender" != "" ]] && echo "MAIL_SENDER=$(encode "$mail_sender")"
|
||||
[[ "$mail_transport" != "null" ]] && echo "MAIL_TRANSPORT=$(encode "$mail_transport")"
|
||||
[[ "$mail_imprint" != "" ]] && echo "MAIL_IMPRINT=$(encode "$mail_imprint")"
|
||||
echo "DISABLE_SIGNUP=$disable_signup"
|
||||
) > /etc/timelimit/env
|
||||
EOF
|
||||
chmod u+x /var/lib/timelimit/build-env.sh
|
||||
/var/lib/timelimit/build-env.sh
|
||||
|
||||
# create a systemd unit and start the server
|
||||
cat > /etc/systemd/system/timelimit.service <<"EOF"
|
||||
[Unit]
|
||||
Description=the timelimit server application
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/var/lib/timelimit/run/
|
||||
RuntimeDirectory=timelimit
|
||||
ExecStartPre=rm -f /var/run/timelimit/server
|
||||
ExecStart=/usr/bin/node /var/lib/timelimit/run/build/index.js
|
||||
User=timelimitrun
|
||||
Group=timelimitrun
|
||||
Restart=always
|
||||
PrivateTmp=yes
|
||||
ProtectSystem=yes
|
||||
ProtectHome=yes
|
||||
ProtectDevices=yes
|
||||
UMask=0555
|
||||
|
||||
Environment="DATABASE_URL=postgres://timelimitrun:unused@localhost/timelimit?host=/var/run/postgresql"
|
||||
Environment="PORT=/var/run/timelimit/server"
|
||||
Environment="NODE_ENV=production"
|
||||
Environment="ALWAYS_PRO=yes"
|
||||
EnvironmentFile=/etc/timelimit/env
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now timelimit.service
|
||||
|
||||
# create timelimit-dump
|
||||
cat > /bin/timelimit-dump <<"EOF"
|
||||
#! /bin/bash
|
||||
set -e
|
||||
if [ "$(id -u)" != 0 ]; then
|
||||
echo "You must run this as root (with sudo)"
|
||||
exit 1
|
||||
fi
|
||||
runuser -u postgres -- pg_dump timelimit
|
||||
EOF
|
||||
chmod +x /bin/timelimit-dump
|
||||
|
||||
# implement timelimit-restore
|
||||
cat > /bin/timelimit-restore <<"EOF"
|
||||
#! /bin/bash
|
||||
set -e
|
||||
if [ "$(id -u)" != 0 ]; then
|
||||
echo "You must run this as root (with sudo)"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$#" != 1 ]; then
|
||||
echo "You must supply one parameter, the file with the data to restore"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "$1" ]; then
|
||||
echo "You supplied a parameter, but it wasn't a file"
|
||||
exit 1
|
||||
fi
|
||||
TEMPFILE="$(mktemp)"
|
||||
chown root "$TEMPFILE"
|
||||
chgrp postgres "$TEMPFILE"
|
||||
chmod u=rw,g=r,o= "$TEMPFILE"
|
||||
cat "$1" > "$TEMPFILE"
|
||||
dialog --yesno "Restoring \"$1\" will delete the current database content. Do you want to continue?" 8 60
|
||||
systemctl stop timelimit
|
||||
runuser -u postgres -- dropdb timelimit
|
||||
runuser -u postgres -- createdb --encoding=utf8 --owner=timelimitrun timelimit
|
||||
runuser -u postgres -- psql -f "$TEMPFILE" --dbname=timelimit
|
||||
rm "$TEMPFILE"
|
||||
systemctl start timelimit
|
||||
dialog --msgbox "The backup was restored." 8 60
|
||||
EOF
|
||||
chmod +x /bin/timelimit-restore
|
||||
|
||||
# create timelimit-upgrade
|
||||
cat > /bin/timelimit-upgrade <<"EOF"
|
||||
#! /bin/bash
|
||||
set -e
|
||||
if [ "$(id -u)" != 0 ]; then
|
||||
echo "You must run this as root (with sudo)"
|
||||
exit 1
|
||||
fi
|
||||
runuser -u timelimitbuild -- /var/lib/timelimit/build/build.sh
|
||||
/var/lib/timelimit/copy-new-build.sh
|
||||
systemctl restart timelimit.service
|
||||
dialog --msgbox "The new timelimit server version was installed." 8 60
|
||||
EOF
|
||||
chmod +x /bin/timelimit-upgrade
|
||||
|
||||
# create timelimit-config
|
||||
cat > /bin/timelimit-config <<"EOF"
|
||||
#! /bin/bash
|
||||
set -e
|
||||
if [ "$(id -u)" != 0 ]; then
|
||||
echo "You must run this as root (with sudo)"
|
||||
exit 1
|
||||
fi
|
||||
configfilepath=/etc/timelimit/config.json
|
||||
config_write() {
|
||||
new_config="$(jq --null-input --argjson 'oldConfig' "$(cat /etc/timelimit/config.json)" "$@")"
|
||||
[[ "$new_config" == "" ]] && return 1
|
||||
echo "$new_config" > /etc/timelimit/config.json
|
||||
/var/lib/timelimit/build-env.sh
|
||||
systemctl restart timelimit
|
||||
}
|
||||
config_whitelist() {
|
||||
config="$(cat "$configfilepath")"
|
||||
|
||||
old_whitelist="$(jq --argjson config "$config" --null-input --raw-output '$config.mailWhitelist | if type == "string" then . else "" end')"
|
||||
mail_whitelist="`dialog --inputbox "Which users are allowed to sign in? This is a list of mail addresses (someone@somewhere.com) or domains (mailbox.org), separated by comma; if a user requests signing in with a mail address which is not in this list, then the request is rejected" 12 60 "$old_whitelist" 3>&1 1>&2 2>&3`"
|
||||
[[ $? -eq 0 ]] || return 0
|
||||
|
||||
config_write --arg whitelist "$mail_whitelist" '$oldConfig + { mailWhitelist: $whitelist }' || return 1
|
||||
|
||||
dialog --msgbox "The whitelist was saved. It is now \"$mail_whitelist\"." 8 60
|
||||
}
|
||||
config_mail_delivery() {
|
||||
config="$(cat "$configfilepath")"
|
||||
|
||||
old_sender="$(jq --argjson config "$config" --null-input --raw-output '$config.mailTransport.sender | if type == "string" then . else "" end')"
|
||||
sender_mail="`dialog --inputbox "From which mail address do you want to send the mails. It's recommend to NOT use your primary mail address." 10 60 "$old_sender" 3>&1 1>&2 2>&3`"
|
||||
[[ $? -eq 0 ]] || return 0
|
||||
|
||||
old_host="$(jq --argjson config "$config" --null-input --raw-output '$config.mailTransport.host | if type == "string" then . else "" end')"
|
||||
sender_host="`dialog --inputbox "What's the hostname of the SMTP server which should be used?" 10 60 "$old_host" 3>&1 1>&2 2>&3`"
|
||||
[[ $? -eq 0 ]] || return 0
|
||||
|
||||
old_secure="$(jq --argjson config "$config" --null-input --raw-output '$config.mailTransport.secure | if type == "boolean" and . == false then "--defaultno" else "" end')"
|
||||
sender_secure=true
|
||||
dialog $old_secure --yesno "Do you want to use TLS when connecting to the mail server?" 8 60 || sender_secure=false
|
||||
|
||||
recommend_port=465
|
||||
if [[ "$sender_secure" == "false" ]]; then
|
||||
recommend_port=587
|
||||
fi
|
||||
|
||||
old_port="$(jq --arg fallback "$recommend_port" --argjson config "$config" --null-input --raw-output '$config.mailTransport.port | if type == "number" then . else $fallback end')"
|
||||
sender_port="`dialog --inputbox "Which port should be used for SMTP? It's most likely ${recommend_port}." 10 60 "$old_port" 3>&1 1>&2 2>&3`"
|
||||
[[ $? -eq 0 ]] || return 0
|
||||
|
||||
old_user="$(jq --argjson config "$config" --null-input --raw-output '$config.mailTransport.user | if type == "string" then . else "" end')"
|
||||
sender_user="`dialog --inputbox "What's the SMTP username?" 10 60 "$old_user" 3>&1 1>&2 2>&3`"
|
||||
[[ $? -eq 0 ]] || return 0
|
||||
|
||||
old_pass="$(jq --argjson config "$config" --null-input --raw-output '$config.mailTransport.pass | if type == "string" then . else "" end')"
|
||||
sender_pass="`dialog --inputbox "What's the SMTP password?" 10 60 "$old_pass" 3>&1 1>&2 2>&3`"
|
||||
[[ $? -eq 0 ]] || return 0
|
||||
|
||||
dialog --yesno "Do you want to use this settings?\nSender: $sender_mail\nHost: $sender_host\nTLS: $sender_secure\nPort: $sender_port\nUser: $sender_user\nPassword: $sender_pass" 11 60 || return 0
|
||||
|
||||
config_write --arg sender "$sender_mail" --arg host "$sender_host" --argjson secure "$sender_secure" --arg port "$sender_port" --arg user "$sender_user" --arg pass "$sender_pass" '$oldConfig + {mailTransport: { sender: $sender, secure: $secure, host: $host, port: $port | tonumber, user: $user, pass: $pass }}' || return 1
|
||||
|
||||
dialog --msgbox "Your settings were saved" 8 60
|
||||
}
|
||||
config_imprint() {
|
||||
config="$(cat "$configfilepath")"
|
||||
|
||||
old_imprint="$(jq --argjson config "$config" --null-input --raw-output '$config.mailImprint | if type == "string" then . else "" end')"
|
||||
imprint="`dialog --inputbox "What footer would you like to set for the sent mails?" 10 60 "$old_imprint" 3>&1 1>&2 2>&3`"
|
||||
[[ $? -eq 0 ]] || return 0
|
||||
|
||||
config_write --arg imprint "$imprint" '$oldConfig + { mailImprint: $imprint }' || return 1
|
||||
|
||||
dialog --msgbox "The footer was saved. It is now \"$imprint\"." 8 60
|
||||
}
|
||||
config_signup() {
|
||||
old_value="$(jq --argjson config "$config" --null-input --raw-output '$config.disableSignup | if type == "boolean" and . == true then "--defaultno" else "" end')"
|
||||
|
||||
value=false
|
||||
dialog $old_value --no-label "Disable sign up" --yes-label "Enable sign up" --yesno "Do you want to allow new users to sign up?" 8 60 || value=true
|
||||
config_write --argjson value "$value" '$oldConfig + {disableSignup: $value}' || return 1
|
||||
if [[ "$value" == "false" ]]; then
|
||||
dialog --msgbox "Users CAN sign up now" 8 60
|
||||
else
|
||||
dialog --msgbox "Users CAN NOT sign up now" 8 60
|
||||
fi
|
||||
}
|
||||
config_main() {
|
||||
config="$(cat "$configfilepath")"
|
||||
mail_whitelist="$(jq --argjson config "$config" --null-input --raw-output '$config.mailWhitelist | if type == "string" then . else "" end')"
|
||||
mail_sender="$(jq --argjson config "$config" --null-input --raw-output '$config.mailTransport.sender | if type == "string" then . else "(not configured)" end')"
|
||||
mail_imprint="$(jq --argjson config "$config" --null-input --raw-output '$config.mailImprint | if type == "string" then . else "" end')"
|
||||
disable_signup="$(jq --argjson config "$config" --null-input --raw-output '$config.disableSignup | if type == "boolean" and . == true then "CAN NOT" else "CAN" end')"
|
||||
|
||||
option="$(dialog --menu "What would you like to change?" 12 0 5 \
|
||||
"mail-whitelist" "The allowed mail addresses for signing in - currently \"$mail_whitelist\"" \
|
||||
"mail-delivery" "The parameters for sending mails - currently using $mail_sender" \
|
||||
"mail-imprint" "The footer of the mails - currently \"$mail_imprint\"" \
|
||||
"disable-signup" "Allow/disallow new users; currently new users $disable_signup sign up" \
|
||||
"nothing" "Close the settings" \
|
||||
3>&1 1>&2 2>&3)"
|
||||
|
||||
[[ $? -eq 0 ]] || return 0
|
||||
|
||||
if [[ "$option" == "mail-whitelist" ]]; then
|
||||
config_whitelist || return 1
|
||||
elif [[ "$option" == "mail-delivery" ]]; then
|
||||
config_mail_delivery || return 1
|
||||
elif [[ "$option" == "mail-imprint" ]]; then
|
||||
config_imprint || return 1
|
||||
elif [[ "$option" == "disable-signup" ]]; then
|
||||
config_signup || return 1
|
||||
elif [[ "$option" == "nothing" ]]; then
|
||||
exit 0
|
||||
else
|
||||
echo "unknown option"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
while true; do
|
||||
config_main
|
||||
done
|
||||
EOF
|
||||
chmod +x /bin/timelimit-config
|
||||
|
||||
dialog --msgbox "Installation finished. You have to configure the mail delivery before you can use your server. You will get a list of possible commands after confirming this message." 8 60
|
||||
reset
|
||||
cat <<"EOF"
|
||||
There are the following new commands available at your system now:
|
||||
|
||||
timelimit-dump
|
||||
This will output the current database content; redirect the output, e.g.
|
||||
using 'timelimit-dump > backup' to create a backup
|
||||
timelimit-restore
|
||||
Use this to restore a dump using 'timelimit-restore ./backup'
|
||||
timelimit-upgrade
|
||||
Use this to upgrade the timelimit server installation
|
||||
timelimit-config
|
||||
Use this to adjust your configuration of the timelimit-server
|
||||
|
||||
You can get a list of them using 'timelimit-<tab>' or by look at the source code
|
||||
of the installation script. This message is written at the end of the script.
|
||||
EOF
|
||||
+57
-55
@@ -53,84 +53,84 @@
|
||||
- [ParentPassword](./serializedchildaction-definitions-parentpassword.md) – `https://timelimit.io/SerializedChildAction#/definitions/ParentPassword`
|
||||
- [ParentPassword](./serializedchildaction-definitions-serializedchildchangepasswordaction-properties-parentpassword.md) – `https://timelimit.io/SerializedChildAction#/definitions/SerializedChildChangePasswordAction/properties/password`
|
||||
- [ParentPassword](./serializedchildaction-definitions-serializedchildchangepasswordaction-properties-parentpassword.md) – `https://timelimit.io/SerializedChildAction#/definitions/SerializedChildChangePasswordAction/properties/password`
|
||||
- [SerialiezdTriedDisablingDeviceAdminAction](./serializedapplogicaction-definitions-serialiezdtrieddisablingdeviceadminaction.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerialiezdTriedDisablingDeviceAdminAction`
|
||||
- [SerialiezdTriedDisablingDeviceAdminAction](./serializedapplogicaction-anyof-serialiezdtrieddisablingdeviceadminaction.md) – `https://timelimit.io/SerializedAppLogicAction#/anyOf/7`
|
||||
- [SerialiezdTriedDisablingDeviceAdminAction](./serializedapplogicaction-definitions-serialiezdtrieddisablingdeviceadminaction.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerialiezdTriedDisablingDeviceAdminAction`
|
||||
- [SerialiizedUpdateNetworkTimeVerificationAction](./serializedparentaction-definitions-serialiizedupdatenetworktimeverificationaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerialiizedUpdateNetworkTimeVerificationAction`
|
||||
- [SerialiizedUpdateNetworkTimeVerificationAction](./serializedparentaction-anyof-serialiizedupdatenetworktimeverificationaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/40`
|
||||
- [SerialiizedUpdateNetworkTimeVerificationAction](./serializedparentaction-anyof-serialiizedupdatenetworktimeverificationaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/41`
|
||||
- [SerializeResetCategoryNetworkIdsAction](./serializedparentaction-definitions-serializeresetcategorynetworkidsaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializeResetCategoryNetworkIdsAction`
|
||||
- [SerializeResetCategoryNetworkIdsAction](./serializedparentaction-anyof-serializeresetcategorynetworkidsaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/14`
|
||||
- [SerializedAddCategoryAppsAction](./serializedparentaction-definitions-serializedaddcategoryappsaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedAddCategoryAppsAction`
|
||||
- [SerializedAddCategoryAppsAction](./serializedparentaction-anyof-serializedaddcategoryappsaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/0`
|
||||
- [SerializedAddCategoryNetworkIdAction](./serializedparentaction-definitions-serializedaddcategorynetworkidaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedAddCategoryNetworkIdAction`
|
||||
- [SerializedAddCategoryNetworkIdAction](./serializedparentaction-anyof-serializedaddcategorynetworkidaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/1`
|
||||
- [SerializedAddInstalledAppsAction](./serializedapplogicaction-definitions-serializedaddinstalledappsaction.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedAddInstalledAppsAction`
|
||||
- [SerializedAddCategoryNetworkIdAction](./serializedparentaction-definitions-serializedaddcategorynetworkidaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedAddCategoryNetworkIdAction`
|
||||
- [SerializedAddInstalledAppsAction](./serializedapplogicaction-anyof-serializedaddinstalledappsaction.md) – `https://timelimit.io/SerializedAppLogicAction#/anyOf/0`
|
||||
- [SerializedAddUsedTimeAction](./serializedapplogicaction-anyof-serializedaddusedtimeaction.md) – `https://timelimit.io/SerializedAppLogicAction#/anyOf/1`
|
||||
- [SerializedAddInstalledAppsAction](./serializedapplogicaction-definitions-serializedaddinstalledappsaction.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedAddInstalledAppsAction`
|
||||
- [SerializedAddUsedTimeAction](./serializedapplogicaction-definitions-serializedaddusedtimeaction.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedAddUsedTimeAction`
|
||||
- [SerializedAddUsedTimeActionVersion2](./serializedapplogicaction-definitions-serializedaddusedtimeactionversion2.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedAddUsedTimeActionVersion2`
|
||||
- [SerializedAddUsedTimeAction](./serializedapplogicaction-anyof-serializedaddusedtimeaction.md) – `https://timelimit.io/SerializedAppLogicAction#/anyOf/1`
|
||||
- [SerializedAddUsedTimeActionVersion2](./serializedapplogicaction-anyof-serializedaddusedtimeactionversion2.md) – `https://timelimit.io/SerializedAppLogicAction#/anyOf/2`
|
||||
- [SerializedAddUserAction](./serializedparentaction-anyof-serializedadduseraction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/2`
|
||||
- [SerializedAddUsedTimeActionVersion2](./serializedapplogicaction-definitions-serializedaddusedtimeactionversion2.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedAddUsedTimeActionVersion2`
|
||||
- [SerializedAddUserAction](./serializedparentaction-definitions-serializedadduseraction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedAddUserAction`
|
||||
- [SerializedAppActivityItem](./serializedapplogicaction-definitions-serializedappactivityitem.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedAppActivityItem`
|
||||
- [SerializedAddUserAction](./serializedparentaction-anyof-serializedadduseraction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/2`
|
||||
- [SerializedAppActivityItem](./serverdatastatus-definitions-serverinstalledappsdata-properties-activities-serializedappactivityitem.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerInstalledAppsData/properties/activities/items`
|
||||
- [SerializedAppActivityItem](./serverdatastatus-definitions-serverinstalledappsdata-properties-activities-serializedappactivityitem.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerInstalledAppsData/properties/activities/items`
|
||||
- [SerializedAppActivityItem](./serializedapplogicaction-definitions-serializedupdateappactivitiesaction-properties-updatedoradded-serializedappactivityitem.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateAppActivitiesAction/properties/updatedOrAdded/items`
|
||||
- [SerializedAppActivityItem](./serializedapplogicaction-definitions-serializedupdateappactivitiesaction-properties-updatedoradded-serializedappactivityitem.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateAppActivitiesAction/properties/updatedOrAdded/items`
|
||||
- [SerializedAppActivityItem](./serverdatastatus-definitions-serializedappactivityitem.md) – `https://timelimit.io/ServerDataStatus#/definitions/SerializedAppActivityItem`
|
||||
- [SerializedAppActivityItem](./serializedapplogicaction-definitions-serializedupdateappactivitiesaction-properties-updatedoradded-serializedappactivityitem.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateAppActivitiesAction/properties/updatedOrAdded/items`
|
||||
- [SerializedAppActivityItem](./serverdatastatus-definitions-serverinstalledappsdata-properties-activities-serializedappactivityitem.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerInstalledAppsData/properties/activities/items`
|
||||
- [SerializedAppActivityItem](./serializedapplogicaction-definitions-serializedupdateappactivitiesaction-properties-updatedoradded-serializedappactivityitem.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateAppActivitiesAction/properties/updatedOrAdded/items`
|
||||
- [SerializedAppActivityItem](./serverdatastatus-definitions-serverinstalledappsdata-properties-activities-serializedappactivityitem.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerInstalledAppsData/properties/activities/items`
|
||||
- [SerializedChangeParentPasswordAction](./serializedparentaction-anyof-serializedchangeparentpasswordaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/3`
|
||||
- [SerializedAppActivityItem](./serializedapplogicaction-definitions-serializedappactivityitem.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedAppActivityItem`
|
||||
- [SerializedChangeParentPasswordAction](./serializedparentaction-definitions-serializedchangeparentpasswordaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedChangeParentPasswordAction`
|
||||
- [SerializedChildChangePasswordAction](./serializedchildaction-anyof-serializedchildchangepasswordaction.md) – `https://timelimit.io/SerializedChildAction#/anyOf/0`
|
||||
- [SerializedChangeParentPasswordAction](./serializedparentaction-anyof-serializedchangeparentpasswordaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/3`
|
||||
- [SerializedChildChangePasswordAction](./serializedchildaction-definitions-serializedchildchangepasswordaction.md) – `https://timelimit.io/SerializedChildAction#/definitions/SerializedChildChangePasswordAction`
|
||||
- [SerializedChildSignInAction](./serializedchildaction-anyof-serializedchildsigninaction.md) – `https://timelimit.io/SerializedChildAction#/anyOf/1`
|
||||
- [SerializedChildChangePasswordAction](./serializedchildaction-anyof-serializedchildchangepasswordaction.md) – `https://timelimit.io/SerializedChildAction#/anyOf/0`
|
||||
- [SerializedChildSignInAction](./serializedchildaction-definitions-serializedchildsigninaction.md) – `https://timelimit.io/SerializedChildAction#/definitions/SerializedChildSignInAction`
|
||||
- [SerializedCreateCategoryAction](./serializedparentaction-anyof-serializedcreatecategoryaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/4`
|
||||
- [SerializedChildSignInAction](./serializedchildaction-anyof-serializedchildsigninaction.md) – `https://timelimit.io/SerializedChildAction#/anyOf/1`
|
||||
- [SerializedCreateCategoryAction](./serializedparentaction-definitions-serializedcreatecategoryaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedCreateCategoryAction`
|
||||
- [SerializedCreateCategoryAction](./serializedparentaction-anyof-serializedcreatecategoryaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/4`
|
||||
- [SerializedCreateTimelimtRuleAction](./serializedparentaction-definitions-serializedcreatetimelimtruleaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedCreateTimelimtRuleAction`
|
||||
- [SerializedCreateTimelimtRuleAction](./serializedparentaction-anyof-serializedcreatetimelimtruleaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/5`
|
||||
- [SerializedDeleteCategoryAction](./serializedparentaction-anyof-serializeddeletecategoryaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/6`
|
||||
- [SerializedDeleteCategoryAction](./serializedparentaction-definitions-serializeddeletecategoryaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedDeleteCategoryAction`
|
||||
- [SerializedDeleteChildTaskAction](./serializedparentaction-anyof-serializeddeletechildtaskaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/7`
|
||||
- [SerializedDeleteChildTaskAction](./serializedparentaction-definitions-serializeddeletechildtaskaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedDeleteChildTaskAction`
|
||||
- [SerializedDeleteChildTaskAction](./serializedparentaction-anyof-serializeddeletechildtaskaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/7`
|
||||
- [SerializedDeleteTimeLimitRuleAction](./serializedparentaction-anyof-serializeddeletetimelimitruleaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/8`
|
||||
- [SerializedDeleteTimeLimitRuleAction](./serializedparentaction-definitions-serializeddeletetimelimitruleaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedDeleteTimeLimitRuleAction`
|
||||
- [SerializedForceSyncAction](./serializedapplogicaction-anyof-serializedforcesyncaction.md) – `https://timelimit.io/SerializedAppLogicAction#/anyOf/3`
|
||||
- [SerializedForceSyncAction](./serializedapplogicaction-definitions-serializedforcesyncaction.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedForceSyncAction`
|
||||
- [SerializedIgnoreManipulationAction](./serializedparentaction-anyof-serializedignoremanipulationaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/9`
|
||||
- [SerializedIgnoreManipulationAction](./serializedparentaction-definitions-serializedignoremanipulationaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedIgnoreManipulationAction`
|
||||
- [SerializedIncrementCategoryExtraTimeAction](./serializedparentaction-definitions-serializedincrementcategoryextratimeaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedIncrementCategoryExtraTimeAction`
|
||||
- [SerializedIncrementCategoryExtraTimeAction](./serializedparentaction-anyof-serializedincrementcategoryextratimeaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/10`
|
||||
- [SerializedIncrementCategoryExtraTimeAction](./serializedparentaction-definitions-serializedincrementcategoryextratimeaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedIncrementCategoryExtraTimeAction`
|
||||
- [SerializedInstalledApp](./serializedapplogicaction-definitions-serializedaddinstalledappsaction-properties-apps-serializedinstalledapp.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedAddInstalledAppsAction/properties/apps/items`
|
||||
- [SerializedInstalledApp](./serializedapplogicaction-definitions-serializedinstalledapp.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedInstalledApp`
|
||||
- [SerializedInstalledApp](./serializedapplogicaction-definitions-serializedaddinstalledappsaction-properties-apps-serializedinstalledapp.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedAddInstalledAppsAction/properties/apps/items`
|
||||
- [SerializedInstalledApp](./serverdatastatus-definitions-serverinstalledappsdata-properties-apps-serializedinstalledapp.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerInstalledAppsData/properties/apps/items`
|
||||
- [SerializedInstalledApp](./serverdatastatus-definitions-serverinstalledappsdata-properties-apps-serializedinstalledapp.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerInstalledAppsData/properties/apps/items`
|
||||
- [SerializedInstalledApp](./serverdatastatus-definitions-serializedinstalledapp.md) – `https://timelimit.io/ServerDataStatus#/definitions/SerializedInstalledApp`
|
||||
- [SerializedInstalledApp](./serializedapplogicaction-definitions-serializedaddinstalledappsaction-properties-apps-serializedinstalledapp.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedAddInstalledAppsAction/properties/apps/items`
|
||||
- [SerializedInstalledApp](./serverdatastatus-definitions-serverinstalledappsdata-properties-apps-serializedinstalledapp.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerInstalledAppsData/properties/apps/items`
|
||||
- [SerializedMarkTaskPendingAction](./serializedapplogicaction-definitions-serializedmarktaskpendingaction.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedMarkTaskPendingAction`
|
||||
- [SerializedMarkTaskPendingAction](./serializedapplogicaction-anyof-serializedmarktaskpendingaction.md) – `https://timelimit.io/SerializedAppLogicAction#/anyOf/4`
|
||||
- [SerializedRemoveCategoryAppsAction](./serializedparentaction-definitions-serializedremovecategoryappsaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveCategoryAppsAction`
|
||||
- [SerializedRemoveCategoryAppsAction](./serializedparentaction-anyof-serializedremovecategoryappsaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/11`
|
||||
- [SerializedRemoveInstalledAppsAction](./serializedapplogicaction-anyof-serializedremoveinstalledappsaction.md) – `https://timelimit.io/SerializedAppLogicAction#/anyOf/5`
|
||||
- [SerializedRemoveCategoryAppsAction](./serializedparentaction-definitions-serializedremovecategoryappsaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveCategoryAppsAction`
|
||||
- [SerializedRemoveInstalledAppsAction](./serializedapplogicaction-definitions-serializedremoveinstalledappsaction.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedRemoveInstalledAppsAction`
|
||||
- [SerializedRemoveUserAction](./serializedparentaction-definitions-serializedremoveuseraction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveUserAction`
|
||||
- [SerializedRemoveInstalledAppsAction](./serializedapplogicaction-anyof-serializedremoveinstalledappsaction.md) – `https://timelimit.io/SerializedAppLogicAction#/anyOf/5`
|
||||
- [SerializedRemoveUserAction](./serializedparentaction-anyof-serializedremoveuseraction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/12`
|
||||
- [SerializedRenameChildAction](./serializedparentaction-definitions-serializedrenamechildaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedRenameChildAction`
|
||||
- [SerializedRemoveUserAction](./serializedparentaction-definitions-serializedremoveuseraction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveUserAction`
|
||||
- [SerializedRenameChildAction](./serializedparentaction-anyof-serializedrenamechildaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/13`
|
||||
- [SerializedRenameChildAction](./serializedparentaction-definitions-serializedrenamechildaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedRenameChildAction`
|
||||
- [SerializedReviewChildTaskAction](./serializedparentaction-definitions-serializedreviewchildtaskaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedReviewChildTaskAction`
|
||||
- [SerializedReviewChildTaskAction](./serializedparentaction-anyof-serializedreviewchildtaskaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/15`
|
||||
- [SerializedSetCategoryExtraTimeAction](./serializedparentaction-anyof-serializedsetcategoryextratimeaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/16`
|
||||
- [SerializedSetCategoryExtraTimeAction](./serializedparentaction-definitions-serializedsetcategoryextratimeaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedSetCategoryExtraTimeAction`
|
||||
- [SerializedSetCategoryForUnassignedAppsAction](./serializedparentaction-definitions-serializedsetcategoryforunassignedappsaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedSetCategoryForUnassignedAppsAction`
|
||||
- [SerializedSetCategoryForUnassignedAppsAction](./serializedparentaction-anyof-serializedsetcategoryforunassignedappsaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/17`
|
||||
- [SerializedSetChildPasswordAction](./serializedparentaction-anyof-serializedsetchildpasswordaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/18`
|
||||
- [SerializedSetCategoryForUnassignedAppsAction](./serializedparentaction-definitions-serializedsetcategoryforunassignedappsaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedSetCategoryForUnassignedAppsAction`
|
||||
- [SerializedSetChildPasswordAction](./serializedparentaction-definitions-serializedsetchildpasswordaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedSetChildPasswordAction`
|
||||
- [SerializedSetChildPasswordAction](./serializedparentaction-anyof-serializedsetchildpasswordaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/18`
|
||||
- [SerializedSetConsiderRebootManipulationAction](./serializedparentaction-anyof-serializedsetconsiderrebootmanipulationaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/19`
|
||||
- [SerializedSetConsiderRebootManipulationAction](./serializedparentaction-definitions-serializedsetconsiderrebootmanipulationaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedSetConsiderRebootManipulationAction`
|
||||
- [SerializedSetDeviceDefaultUserAction](./serializedparentaction-definitions-serializedsetdevicedefaultuseraction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedSetDeviceDefaultUserAction`
|
||||
- [SerializedSetDeviceDefaultUserAction](./serializedparentaction-anyof-serializedsetdevicedefaultuseraction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/20`
|
||||
- [SerializedSetDeviceDefaultUserTimeoutAction](./serializedparentaction-definitions-serializedsetdevicedefaultusertimeoutaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedSetDeviceDefaultUserTimeoutAction`
|
||||
- [SerializedSetDeviceDefaultUserTimeoutAction](./serializedparentaction-anyof-serializedsetdevicedefaultusertimeoutaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/21`
|
||||
- [SerializedSetDeviceUserAction](./serializedparentaction-definitions-serializedsetdeviceuseraction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedSetDeviceUserAction`
|
||||
- [SerializedSetDeviceDefaultUserTimeoutAction](./serializedparentaction-definitions-serializedsetdevicedefaultusertimeoutaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedSetDeviceDefaultUserTimeoutAction`
|
||||
- [SerializedSetDeviceUserAction](./serializedparentaction-anyof-serializedsetdeviceuseraction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/22`
|
||||
- [SerializedSetDeviceUserAction](./serializedparentaction-definitions-serializedsetdeviceuseraction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedSetDeviceUserAction`
|
||||
- [SerializedSetKeepSignedInAction](./serializedparentaction-definitions-serializedsetkeepsignedinaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedSetKeepSignedInAction`
|
||||
- [SerializedSetKeepSignedInAction](./serializedparentaction-anyof-serializedsetkeepsignedinaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/23`
|
||||
- [SerializedSetParentCategoryAction](./serializedparentaction-definitions-serializedsetparentcategoryaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedSetParentCategoryAction`
|
||||
@@ -141,71 +141,73 @@
|
||||
- [SerializedSetSendDeviceConnected](./serializedparentaction-anyof-serializedsetsenddeviceconnected.md) – `https://timelimit.io/SerializedParentAction#/anyOf/26`
|
||||
- [SerializedSetUserDisableLimitsUntilAction](./serializedparentaction-definitions-serializedsetuserdisablelimitsuntilaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedSetUserDisableLimitsUntilAction`
|
||||
- [SerializedSetUserDisableLimitsUntilAction](./serializedparentaction-anyof-serializedsetuserdisablelimitsuntilaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/27`
|
||||
- [SerializedSetUserTimezoneAction](./serializedparentaction-anyof-serializedsetusertimezoneaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/28`
|
||||
- [SerializedSetUserTimezoneAction](./serializedparentaction-definitions-serializedsetusertimezoneaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedSetUserTimezoneAction`
|
||||
- [SerializedSignOutAtDeviceAction](./serializedapplogicaction-anyof-serializedsignoutatdeviceaction.md) – `https://timelimit.io/SerializedAppLogicAction#/anyOf/6`
|
||||
- [SerializedSetUserTimezoneAction](./serializedparentaction-anyof-serializedsetusertimezoneaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/28`
|
||||
- [SerializedSignOutAtDeviceAction](./serializedapplogicaction-definitions-serializedsignoutatdeviceaction.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedSignOutAtDeviceAction`
|
||||
- [SerializedSignOutAtDeviceAction](./serializedapplogicaction-anyof-serializedsignoutatdeviceaction.md) – `https://timelimit.io/SerializedAppLogicAction#/anyOf/6`
|
||||
- [SerializedTimeLimitRule](./serializedparentaction-definitions-serializedcreatetimelimtruleaction-properties-serializedtimelimitrule.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedCreateTimelimtRuleAction/properties/rule`
|
||||
- [SerializedTimeLimitRule](./serializedparentaction-definitions-serializedcreatetimelimtruleaction-properties-serializedtimelimitrule.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedCreateTimelimtRuleAction/properties/rule`
|
||||
- [SerializedTimeLimitRule](./serializedparentaction-definitions-serializedtimelimitrule.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedTimeLimitRule`
|
||||
- [SerializedUpdatCategoryDisableLimitsAction](./serializedparentaction-definitions-serializedupdatcategorydisablelimitsaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdatCategoryDisableLimitsAction`
|
||||
- [SerializedUpdatCategoryDisableLimitsAction](./serializedparentaction-anyof-serializedupdatcategorydisablelimitsaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/32`
|
||||
- [SerializedUpdateAppActivitiesAction](./serializedapplogicaction-definitions-serializedupdateappactivitiesaction.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateAppActivitiesAction`
|
||||
- [SerializedUpdateAppActivitiesAction](./serializedapplogicaction-anyof-serializedupdateappactivitiesaction.md) – `https://timelimit.io/SerializedAppLogicAction#/anyOf/8`
|
||||
- [SerializedUpdateCategoryBatteryLimitAction](./serializedparentaction-definitions-serializedupdatecategorybatterylimitaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryBatteryLimitAction`
|
||||
- [SerializedUpdateAppActivitiesAction](./serializedapplogicaction-definitions-serializedupdateappactivitiesaction.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateAppActivitiesAction`
|
||||
- [SerializedUpdateCategoryBatteryLimitAction](./serializedparentaction-anyof-serializedupdatecategorybatterylimitaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/29`
|
||||
- [SerializedUpdateCategoryBlockAllNotificationsAction](./serializedparentaction-definitions-serializedupdatecategoryblockallnotificationsaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryBlockAllNotificationsAction`
|
||||
- [SerializedUpdateCategoryBatteryLimitAction](./serializedparentaction-definitions-serializedupdatecategorybatterylimitaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryBatteryLimitAction`
|
||||
- [SerializedUpdateCategoryBlockAllNotificationsAction](./serializedparentaction-anyof-serializedupdatecategoryblockallnotificationsaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/30`
|
||||
- [SerializedUpdateCategoryBlockAllNotificationsAction](./serializedparentaction-definitions-serializedupdatecategoryblockallnotificationsaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryBlockAllNotificationsAction`
|
||||
- [SerializedUpdateCategoryBlockedTimesAction](./serializedparentaction-definitions-serializedupdatecategoryblockedtimesaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryBlockedTimesAction`
|
||||
- [SerializedUpdateCategoryBlockedTimesAction](./serializedparentaction-anyof-serializedupdatecategoryblockedtimesaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/31`
|
||||
- [SerializedUpdateCategorySortingAction](./serializedparentaction-anyof-serializedupdatecategorysortingaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/33`
|
||||
- [SerializedUpdateCategoryFlagsAction](./serializedparentaction-anyof-serializedupdatecategoryflagsaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/33`
|
||||
- [SerializedUpdateCategoryFlagsAction](./serializedparentaction-definitions-serializedupdatecategoryflagsaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction`
|
||||
- [SerializedUpdateCategorySortingAction](./serializedparentaction-anyof-serializedupdatecategorysortingaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/34`
|
||||
- [SerializedUpdateCategorySortingAction](./serializedparentaction-definitions-serializedupdatecategorysortingaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategorySortingAction`
|
||||
- [SerializedUpdateCategoryTemporarilyBlockedAction](./serializedparentaction-anyof-serializedupdatecategorytemporarilyblockedaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/34`
|
||||
- [SerializedUpdateCategoryTemporarilyBlockedAction](./serializedparentaction-anyof-serializedupdatecategorytemporarilyblockedaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/35`
|
||||
- [SerializedUpdateCategoryTemporarilyBlockedAction](./serializedparentaction-definitions-serializedupdatecategorytemporarilyblockedaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTemporarilyBlockedAction`
|
||||
- [SerializedUpdateCategoryTimeWarningsAction](./serializedparentaction-anyof-serializedupdatecategorytimewarningsaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/35`
|
||||
- [SerializedUpdateCategoryTimeWarningsAction](./serializedparentaction-anyof-serializedupdatecategorytimewarningsaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/36`
|
||||
- [SerializedUpdateCategoryTimeWarningsAction](./serializedparentaction-definitions-serializedupdatecategorytimewarningsaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTimeWarningsAction`
|
||||
- [SerializedUpdateCategoryTitleAction](./serializedparentaction-anyof-serializedupdatecategorytitleaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/36`
|
||||
- [SerializedUpdateCategoryTitleAction](./serializedparentaction-anyof-serializedupdatecategorytitleaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/37`
|
||||
- [SerializedUpdateCategoryTitleAction](./serializedparentaction-definitions-serializedupdatecategorytitleaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTitleAction`
|
||||
- [SerializedUpdateChildTaskAction](./serializedparentaction-anyof-serializedupdatechildtaskaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/37`
|
||||
- [SerializedUpdateChildTaskAction](./serializedparentaction-definitions-serializedupdatechildtaskaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateChildTaskAction`
|
||||
- [SerializedUpdateDeviceNameAction](./serializedparentaction-anyof-serializedupdatedevicenameaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/38`
|
||||
- [SerializedUpdateChildTaskAction](./serializedparentaction-anyof-serializedupdatechildtaskaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/38`
|
||||
- [SerializedUpdateDeviceNameAction](./serializedparentaction-anyof-serializedupdatedevicenameaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/39`
|
||||
- [SerializedUpdateDeviceNameAction](./serializedparentaction-definitions-serializedupdatedevicenameaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateDeviceNameAction`
|
||||
- [SerializedUpdateDeviceStatusAction](./serializedapplogicaction-anyof-serializedupdatedevicestatusaction.md) – `https://timelimit.io/SerializedAppLogicAction#/anyOf/9`
|
||||
- [SerializedUpdateDeviceStatusAction](./serializedapplogicaction-definitions-serializedupdatedevicestatusaction.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateDeviceStatusAction`
|
||||
- [SerializedUpdateEnableActivityLevelBlockingAction](./serializedparentaction-anyof-serializedupdateenableactivitylevelblockingaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/39`
|
||||
- [SerializedUpdateEnableActivityLevelBlockingAction](./serializedparentaction-anyof-serializedupdateenableactivitylevelblockingaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/40`
|
||||
- [SerializedUpdateEnableActivityLevelBlockingAction](./serializedparentaction-definitions-serializedupdateenableactivitylevelblockingaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateEnableActivityLevelBlockingAction`
|
||||
- [SerializedUpdateParentNotificationFlagsAction](./serializedparentaction-anyof-serializedupdateparentnotificationflagsaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/41`
|
||||
- [SerializedUpdateParentNotificationFlagsAction](./serializedparentaction-anyof-serializedupdateparentnotificationflagsaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/42`
|
||||
- [SerializedUpdateParentNotificationFlagsAction](./serializedparentaction-definitions-serializedupdateparentnotificationflagsaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateParentNotificationFlagsAction`
|
||||
- [SerializedUpdateTimelimitRuleAction](./serializedparentaction-anyof-serializedupdatetimelimitruleaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/42`
|
||||
- [SerializedUpdateTimelimitRuleAction](./serializedparentaction-anyof-serializedupdatetimelimitruleaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/43`
|
||||
- [SerializedUpdateTimelimitRuleAction](./serializedparentaction-definitions-serializedupdatetimelimitruleaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateTimelimitRuleAction`
|
||||
- [SerializedUpdateUserFlagsAction](./serializedparentaction-anyof-serializedupdateuserflagsaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/44`
|
||||
- [SerializedUpdateUserFlagsAction](./serializedparentaction-definitions-serializedupdateuserflagsaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserFlagsAction`
|
||||
- [SerializedUpdateUserFlagsAction](./serializedparentaction-anyof-serializedupdateuserflagsaction.md) – `https://timelimit.io/SerializedParentAction#/anyOf/43`
|
||||
- [SerializedUpdateUserLimitLoginCategory](./serializedparentaction-anyof-serializedupdateuserlimitlogincategory.md) – `https://timelimit.io/SerializedParentAction#/anyOf/44`
|
||||
- [SerializedUpdateUserLimitLoginCategory](./serializedparentaction-anyof-serializedupdateuserlimitlogincategory.md) – `https://timelimit.io/SerializedParentAction#/anyOf/45`
|
||||
- [SerializedUpdateUserLimitLoginCategory](./serializedparentaction-definitions-serializedupdateuserlimitlogincategory.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserLimitLoginCategory`
|
||||
- [SerializedUpdateUserLimitLoginPreBlockDuration](./serializedparentaction-anyof-serializedupdateuserlimitloginpreblockduration.md) – `https://timelimit.io/SerializedParentAction#/anyOf/45`
|
||||
- [SerializedUpdateUserLimitLoginPreBlockDuration](./serializedparentaction-anyof-serializedupdateuserlimitloginpreblockduration.md) – `https://timelimit.io/SerializedParentAction#/anyOf/46`
|
||||
- [SerializedUpdateUserLimitLoginPreBlockDuration](./serializedparentaction-definitions-serializedupdateuserlimitloginpreblockduration.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserLimitLoginPreBlockDuration`
|
||||
- [ServerCategoryNetworkId](./serverdatastatus-definitions-serverupdatedcategorybasedata-properties-networks-servercategorynetworkid.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryBaseData/properties/networks/items`
|
||||
- [ServerCategoryNetworkId](./serverdatastatus-definitions-servercategorynetworkid.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerCategoryNetworkId`
|
||||
- [ServerCategoryNetworkId](./serverdatastatus-definitions-serverupdatedcategorybasedata-properties-networks-servercategorynetworkid.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryBaseData/properties/networks/items`
|
||||
- [ServerCategoryNetworkId](./serverdatastatus-definitions-serverupdatedcategorybasedata-properties-networks-servercategorynetworkid.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryBaseData/properties/networks/items`
|
||||
- [ServerDeviceData](./serverdatastatus-definitions-serverdevicedata.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerDeviceData`
|
||||
- [ServerDeviceData](./serverdatastatus-definitions-serverdevicelist-properties-data-serverdevicedata.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerDeviceList/properties/data/items`
|
||||
- [ServerDeviceData](./serverdatastatus-definitions-serverdevicedata.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerDeviceData`
|
||||
- [ServerDeviceData](./serverdatastatus-definitions-serverdevicelist-properties-data-serverdevicedata.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerDeviceList/properties/data/items`
|
||||
- [ServerDeviceList](./serverdatastatus-properties-serverdevicelist.md) – `https://timelimit.io/ServerDataStatus#/properties/devices`
|
||||
- [ServerDeviceList](./serverdatastatus-definitions-serverdevicelist.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerDeviceList`
|
||||
- [ServerInstalledAppsData](./serverdatastatus-properties-apps-serverinstalledappsdata.md) – `https://timelimit.io/ServerDataStatus#/properties/apps/items`
|
||||
- [ServerInstalledAppsData](./serverdatastatus-definitions-serverinstalledappsdata.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerInstalledAppsData`
|
||||
- [ServerSessionDurationItem](./serverdatastatus-definitions-serverupdatedcategoryusedtimes-properties-sessiondurations-serversessiondurationitem.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryUsedTimes/properties/sessionDurations/items`
|
||||
- [ServerInstalledAppsData](./serverdatastatus-properties-apps-serverinstalledappsdata.md) – `https://timelimit.io/ServerDataStatus#/properties/apps/items`
|
||||
- [ServerSessionDurationItem](./serverdatastatus-definitions-serverupdatedcategoryusedtimes-properties-sessiondurations-serversessiondurationitem.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryUsedTimes/properties/sessionDurations/items`
|
||||
- [ServerSessionDurationItem](./serverdatastatus-definitions-serversessiondurationitem.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerSessionDurationItem`
|
||||
- [ServerSessionDurationItem](./serverdatastatus-definitions-serverupdatedcategoryusedtimes-properties-sessiondurations-serversessiondurationitem.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryUsedTimes/properties/sessionDurations/items`
|
||||
- [ServerTimeLimitRule](./serverdatastatus-definitions-serverupdatedtimelimitrules-properties-rules-servertimelimitrule.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedTimeLimitRules/properties/rules/items`
|
||||
- [ServerTimeLimitRule](./serverdatastatus-definitions-servertimelimitrule.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerTimeLimitRule`
|
||||
- [ServerTimeLimitRule](./serverdatastatus-definitions-serverupdatedtimelimitrules-properties-rules-servertimelimitrule.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedTimeLimitRules/properties/rules/items`
|
||||
- [ServerUpdatedCategoryAssignedApps](./serverdatastatus-properties-categoryapp-serverupdatedcategoryassignedapps.md) – `https://timelimit.io/ServerDataStatus#/properties/categoryApp/items`
|
||||
- [ServerUpdatedCategoryAssignedApps](./serverdatastatus-definitions-serverupdatedcategoryassignedapps.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryAssignedApps`
|
||||
- [ServerUpdatedCategoryAssignedApps](./serverdatastatus-properties-categoryapp-serverupdatedcategoryassignedapps.md) – `https://timelimit.io/ServerDataStatus#/properties/categoryApp/items`
|
||||
- [ServerUpdatedCategoryBaseData](./serverdatastatus-definitions-serverupdatedcategorybasedata.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryBaseData`
|
||||
- [ServerUpdatedCategoryBaseData](./serverdatastatus-properties-categorybase-serverupdatedcategorybasedata.md) – `https://timelimit.io/ServerDataStatus#/properties/categoryBase/items`
|
||||
- [ServerUpdatedCategoryTask](./serverdatastatus-definitions-serverupdatedcategorytask.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryTask`
|
||||
- [ServerUpdatedCategoryTask](./serverdatastatus-definitions-serverupdatedcategorytasks-properties-tasks-serverupdatedcategorytask.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryTasks/properties/tasks/items`
|
||||
- [ServerUpdatedCategoryTask](./serverdatastatus-definitions-serverupdatedcategorytask.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryTask`
|
||||
- [ServerUpdatedCategoryTask](./serverdatastatus-definitions-serverupdatedcategorytasks-properties-tasks-serverupdatedcategorytask.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryTasks/properties/tasks/items`
|
||||
- [ServerUpdatedCategoryTasks](./serverdatastatus-definitions-serverupdatedcategorytasks.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryTasks`
|
||||
- [ServerUpdatedCategoryTasks](./serverdatastatus-properties-tasks-serverupdatedcategorytasks.md) – `https://timelimit.io/ServerDataStatus#/properties/tasks/items`
|
||||
@@ -214,17 +216,17 @@
|
||||
- [ServerUpdatedTimeLimitRules](./serverdatastatus-definitions-serverupdatedtimelimitrules.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedTimeLimitRules`
|
||||
- [ServerUpdatedTimeLimitRules](./serverdatastatus-properties-rules-serverupdatedtimelimitrules.md) – `https://timelimit.io/ServerDataStatus#/properties/rules/items`
|
||||
- [ServerUsedTimeItem](./serverdatastatus-definitions-serverupdatedcategoryusedtimes-properties-times-serverusedtimeitem.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryUsedTimes/properties/times/items`
|
||||
- [ServerUsedTimeItem](./serverdatastatus-definitions-serverupdatedcategoryusedtimes-properties-times-serverusedtimeitem.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryUsedTimes/properties/times/items`
|
||||
- [ServerUsedTimeItem](./serverdatastatus-definitions-serverusedtimeitem.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUsedTimeItem`
|
||||
- [ServerUserEntry](./serverdatastatus-definitions-serveruserlist-properties-data-serveruserentry.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUserList/properties/data/items`
|
||||
- [ServerUserEntry](./serverdatastatus-definitions-serveruserlist-properties-data-serveruserentry.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUserList/properties/data/items`
|
||||
- [ServerUsedTimeItem](./serverdatastatus-definitions-serverupdatedcategoryusedtimes-properties-times-serverusedtimeitem.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryUsedTimes/properties/times/items`
|
||||
- [ServerUserEntry](./serverdatastatus-definitions-serveruserentry.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUserEntry`
|
||||
- [ServerUserEntry](./serverdatastatus-definitions-serveruserlist-properties-data-serveruserentry.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUserList/properties/data/items`
|
||||
- [ServerUserEntry](./serverdatastatus-definitions-serveruserlist-properties-data-serveruserentry.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUserList/properties/data/items`
|
||||
- [ServerUserList](./serverdatastatus-definitions-serveruserlist.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUserList`
|
||||
- [ServerUserList](./serverdatastatus-properties-serveruserlist.md) – `https://timelimit.io/ServerDataStatus#/properties/users`
|
||||
- [Untitled object in ClientPullChangesRequest](./clientpullchangesrequest-definitions-clientdatastatus-properties-apps.md) – `https://timelimit.io/ClientPullChangesRequest#/definitions/ClientDataStatus/properties/apps`
|
||||
- [Untitled object in ClientPullChangesRequest](./clientpullchangesrequest-definitions-clientdatastatus-properties-categories.md) – `https://timelimit.io/ClientPullChangesRequest#/definitions/ClientDataStatus/properties/categories`
|
||||
- [Untitled object in ClientPullChangesRequest](./clientpullchangesrequest-definitions-clientdatastatus-properties-apps.md) – `https://timelimit.io/ClientPullChangesRequest#/definitions/ClientDataStatus/properties/apps`
|
||||
- [Untitled object in ClientPullChangesRequest](./clientpullchangesrequest-definitions-clientdatastatus-properties-categories.md) – `https://timelimit.io/ClientPullChangesRequest#/definitions/ClientDataStatus/properties/categories`
|
||||
- [Untitled object in ClientPullChangesRequest](./clientpullchangesrequest-definitions-clientdatastatus-properties-apps.md) – `https://timelimit.io/ClientPullChangesRequest#/definitions/ClientDataStatus/properties/apps`
|
||||
- [Untitled object in SerializedAppLogicAction](./serializedapplogicaction-definitions-serializedaddusedtimeactionversion2-properties-i-items.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedAddUsedTimeActionVersion2/properties/i/items`
|
||||
- [Untitled object in SerializedAppLogicAction](./serializedapplogicaction-definitions-serializedaddusedtimeactionversion2-properties-i-items.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedAddUsedTimeActionVersion2/properties/i/items`
|
||||
|
||||
|
||||
@@ -99,6 +99,9 @@
|
||||
{
|
||||
"$ref": "#/definitions/SerializedUpdatCategoryDisableLimitsAction"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/SerializedUpdateCategoryFlagsAction"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/SerializedUpdateCategorySortingAction"
|
||||
},
|
||||
@@ -1061,6 +1064,34 @@
|
||||
],
|
||||
"title": "SerializedUpdatCategoryDisableLimitsAction"
|
||||
},
|
||||
"SerializedUpdateCategoryFlagsAction": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"UPDATE_CATEGORY_FLAGS"
|
||||
]
|
||||
},
|
||||
"categoryId": {
|
||||
"type": "string"
|
||||
},
|
||||
"modified": {
|
||||
"type": "number"
|
||||
},
|
||||
"values": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"categoryId",
|
||||
"modified",
|
||||
"type",
|
||||
"values"
|
||||
],
|
||||
"title": "SerializedUpdateCategoryFlagsAction"
|
||||
},
|
||||
"SerializedUpdateCategorySortingAction": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -385,6 +385,9 @@
|
||||
},
|
||||
"dlu": {
|
||||
"type": "number"
|
||||
},
|
||||
"flags": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@@ -396,6 +399,7 @@
|
||||
"dlu",
|
||||
"extraTime",
|
||||
"extraTimeDay",
|
||||
"flags",
|
||||
"mblCharging",
|
||||
"mblMobile",
|
||||
"networks",
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
# Untitled string in SerializedParentAction Schema
|
||||
|
||||
```txt
|
||||
https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/categoryId
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
|
||||
| :------------------ | ---------- | -------------- | ----------------------- | :---------------- | --------------------- | ------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [SerializedParentAction.schema.json\*](SerializedParentAction.schema.json "open original schema") |
|
||||
|
||||
## categoryId Type
|
||||
|
||||
`string`
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
# Untitled number in SerializedParentAction Schema
|
||||
|
||||
```txt
|
||||
https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/modified
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
|
||||
| :------------------ | ---------- | -------------- | ----------------------- | :---------------- | --------------------- | ------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [SerializedParentAction.schema.json\*](SerializedParentAction.schema.json "open original schema") |
|
||||
|
||||
## modified Type
|
||||
|
||||
`number`
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
# Untitled string in SerializedParentAction Schema
|
||||
|
||||
```txt
|
||||
https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/type
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
|
||||
| :------------------ | ---------- | -------------- | ----------------------- | :---------------- | --------------------- | ------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [SerializedParentAction.schema.json\*](SerializedParentAction.schema.json "open original schema") |
|
||||
|
||||
## type Type
|
||||
|
||||
`string`
|
||||
|
||||
## type Constraints
|
||||
|
||||
**enum**: the value of this property must be equal to one of the following values:
|
||||
|
||||
| Value | Explanation |
|
||||
| :------------------------ | ----------- |
|
||||
| `"UPDATE_CATEGORY_FLAGS"` | |
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
# Untitled number in SerializedParentAction Schema
|
||||
|
||||
```txt
|
||||
https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/values
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
|
||||
| :------------------ | ---------- | -------------- | ----------------------- | :---------------- | --------------------- | ------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [SerializedParentAction.schema.json\*](SerializedParentAction.schema.json "open original schema") |
|
||||
|
||||
## values Type
|
||||
|
||||
`number`
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
# Untitled undefined type in SerializedParentAction Schema
|
||||
|
||||
```txt
|
||||
https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
|
||||
| :------------------ | ---------- | -------------- | ----------------------- | :---------------- | --------------------- | ------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [SerializedParentAction.schema.json\*](SerializedParentAction.schema.json "open original schema") |
|
||||
|
||||
## properties Type
|
||||
|
||||
unknown
|
||||
@@ -0,0 +1,97 @@
|
||||
# SerializedUpdateCategoryFlagsAction Schema
|
||||
|
||||
```txt
|
||||
https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
|
||||
| :------------------ | ---------- | -------------- | ------------ | :---------------- | --------------------- | ------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| Can be instantiated | No | Unknown status | No | Forbidden | Forbidden | none | [SerializedParentAction.schema.json\*](SerializedParentAction.schema.json "open original schema") |
|
||||
|
||||
## SerializedUpdateCategoryFlagsAction Type
|
||||
|
||||
`object` ([SerializedUpdateCategoryFlagsAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction.md))
|
||||
|
||||
# SerializedUpdateCategoryFlagsAction Properties
|
||||
|
||||
| Property | Type | Required | Nullable | Defined by |
|
||||
| :------------------------ | -------- | -------- | -------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [type](#type) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/type") |
|
||||
| [categoryId](#categoryid) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/categoryId") |
|
||||
| [modified](#modified) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-modified.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/modified") |
|
||||
| [values](#values) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-values.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/values") |
|
||||
|
||||
## type
|
||||
|
||||
|
||||
|
||||
|
||||
`type`
|
||||
|
||||
- is required
|
||||
- Type: `string`
|
||||
- cannot be null
|
||||
- defined in: [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/type")
|
||||
|
||||
### type Type
|
||||
|
||||
`string`
|
||||
|
||||
### type Constraints
|
||||
|
||||
**enum**: the value of this property must be equal to one of the following values:
|
||||
|
||||
| Value | Explanation |
|
||||
| :------------------------ | ----------- |
|
||||
| `"UPDATE_CATEGORY_FLAGS"` | |
|
||||
|
||||
## categoryId
|
||||
|
||||
|
||||
|
||||
|
||||
`categoryId`
|
||||
|
||||
- is required
|
||||
- Type: `string`
|
||||
- cannot be null
|
||||
- defined in: [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/categoryId")
|
||||
|
||||
### categoryId Type
|
||||
|
||||
`string`
|
||||
|
||||
## modified
|
||||
|
||||
|
||||
|
||||
|
||||
`modified`
|
||||
|
||||
- is required
|
||||
- Type: `number`
|
||||
- cannot be null
|
||||
- defined in: [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-modified.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/modified")
|
||||
|
||||
### modified Type
|
||||
|
||||
`number`
|
||||
|
||||
## values
|
||||
|
||||
|
||||
|
||||
|
||||
`values`
|
||||
|
||||
- is required
|
||||
- Type: `number`
|
||||
- cannot be null
|
||||
- defined in: [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-values.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/values")
|
||||
|
||||
### values Type
|
||||
|
||||
`number`
|
||||
@@ -50,6 +50,7 @@ any of
|
||||
- [SerializedUpdateCategoryBlockAllNotificationsAction](serializedparentaction-definitions-serializedupdatecategoryblockallnotificationsaction.md "check type definition")
|
||||
- [SerializedUpdateCategoryBlockedTimesAction](serializedparentaction-definitions-serializedupdatecategoryblockedtimesaction.md "check type definition")
|
||||
- [SerializedUpdatCategoryDisableLimitsAction](serializedparentaction-definitions-serializedupdatcategorydisablelimitsaction.md "check type definition")
|
||||
- [SerializedUpdateCategoryFlagsAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction.md "check type definition")
|
||||
- [SerializedUpdateCategorySortingAction](serializedparentaction-definitions-serializedupdatecategorysortingaction.md "check type definition")
|
||||
- [SerializedUpdateCategoryTemporarilyBlockedAction](serializedparentaction-definitions-serializedupdatecategorytemporarilyblockedaction.md "check type definition")
|
||||
- [SerializedUpdateCategoryTimeWarningsAction](serializedparentaction-definitions-serializedupdatecategorytimewarningsaction.md "check type definition")
|
||||
@@ -2900,6 +2901,93 @@ Reference this group by using
|
||||
|
||||
`number`
|
||||
|
||||
## Definitions group SerializedUpdateCategoryFlagsAction
|
||||
|
||||
Reference this group by using
|
||||
|
||||
```json
|
||||
{"$ref":"https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction"}
|
||||
```
|
||||
|
||||
| Property | Type | Required | Nullable | Defined by |
|
||||
| :--------------------------- | -------- | -------- | -------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [type](#type-33) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/type") |
|
||||
| [categoryId](#categoryid-15) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/categoryId") |
|
||||
| [modified](#modified) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-modified.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/modified") |
|
||||
| [values](#values) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-values.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/values") |
|
||||
|
||||
### type
|
||||
|
||||
|
||||
|
||||
|
||||
`type`
|
||||
|
||||
- is required
|
||||
- Type: `string`
|
||||
- cannot be null
|
||||
- defined in: [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/type")
|
||||
|
||||
#### type Type
|
||||
|
||||
`string`
|
||||
|
||||
#### type Constraints
|
||||
|
||||
**enum**: the value of this property must be equal to one of the following values:
|
||||
|
||||
| Value | Explanation |
|
||||
| :------------------------ | ----------- |
|
||||
| `"UPDATE_CATEGORY_FLAGS"` | |
|
||||
|
||||
### categoryId
|
||||
|
||||
|
||||
|
||||
|
||||
`categoryId`
|
||||
|
||||
- is required
|
||||
- Type: `string`
|
||||
- cannot be null
|
||||
- defined in: [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/categoryId")
|
||||
|
||||
#### categoryId Type
|
||||
|
||||
`string`
|
||||
|
||||
### modified
|
||||
|
||||
|
||||
|
||||
|
||||
`modified`
|
||||
|
||||
- is required
|
||||
- Type: `number`
|
||||
- cannot be null
|
||||
- defined in: [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-modified.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/modified")
|
||||
|
||||
#### modified Type
|
||||
|
||||
`number`
|
||||
|
||||
### values
|
||||
|
||||
|
||||
|
||||
|
||||
`values`
|
||||
|
||||
- is required
|
||||
- Type: `number`
|
||||
- cannot be null
|
||||
- defined in: [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-values.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/values")
|
||||
|
||||
#### values Type
|
||||
|
||||
`number`
|
||||
|
||||
## Definitions group SerializedUpdateCategorySortingAction
|
||||
|
||||
Reference this group by using
|
||||
@@ -2910,7 +2998,7 @@ Reference this group by using
|
||||
|
||||
| Property | Type | Required | Nullable | Defined by |
|
||||
| :-------------------------- | -------- | -------- | -------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [type](#type-33) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorysortingaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategorySortingAction/properties/type") |
|
||||
| [type](#type-34) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorysortingaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategorySortingAction/properties/type") |
|
||||
| [categoryIds](#categoryids) | `array` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorysortingaction-properties-categoryids.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategorySortingAction/properties/categoryIds") |
|
||||
|
||||
### type
|
||||
@@ -2963,8 +3051,8 @@ Reference this group by using
|
||||
|
||||
| Property | Type | Required | Nullable | Defined by |
|
||||
| :--------------------------- | --------- | -------- | -------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [type](#type-34) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytemporarilyblockedaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTemporarilyBlockedAction/properties/type") |
|
||||
| [categoryId](#categoryid-15) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytemporarilyblockedaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTemporarilyBlockedAction/properties/categoryId") |
|
||||
| [type](#type-35) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytemporarilyblockedaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTemporarilyBlockedAction/properties/type") |
|
||||
| [categoryId](#categoryid-16) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytemporarilyblockedaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTemporarilyBlockedAction/properties/categoryId") |
|
||||
| [blocked](#blocked-1) | `boolean` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytemporarilyblockedaction-properties-blocked.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTemporarilyBlockedAction/properties/blocked") |
|
||||
| [endTime](#endtime-1) | `number` | Optional | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytemporarilyblockedaction-properties-endtime.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTemporarilyBlockedAction/properties/endTime") |
|
||||
|
||||
@@ -3050,8 +3138,8 @@ Reference this group by using
|
||||
|
||||
| Property | Type | Required | Nullable | Defined by |
|
||||
| :--------------------------- | --------- | -------- | -------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [type](#type-35) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytimewarningsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTimeWarningsAction/properties/type") |
|
||||
| [categoryId](#categoryid-16) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytimewarningsaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTimeWarningsAction/properties/categoryId") |
|
||||
| [type](#type-36) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytimewarningsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTimeWarningsAction/properties/type") |
|
||||
| [categoryId](#categoryid-17) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytimewarningsaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTimeWarningsAction/properties/categoryId") |
|
||||
| [enable](#enable-2) | `boolean` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytimewarningsaction-properties-enable.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTimeWarningsAction/properties/enable") |
|
||||
| [flags](#flags) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytimewarningsaction-properties-flags.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTimeWarningsAction/properties/flags") |
|
||||
|
||||
@@ -3137,8 +3225,8 @@ Reference this group by using
|
||||
|
||||
| Property | Type | Required | Nullable | Defined by |
|
||||
| :--------------------------- | -------- | -------- | -------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [type](#type-36) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytitleaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTitleAction/properties/type") |
|
||||
| [categoryId](#categoryid-17) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytitleaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTitleAction/properties/categoryId") |
|
||||
| [type](#type-37) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytitleaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTitleAction/properties/type") |
|
||||
| [categoryId](#categoryid-18) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytitleaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTitleAction/properties/categoryId") |
|
||||
| [newTitle](#newtitle) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytitleaction-properties-newtitle.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTitleAction/properties/newTitle") |
|
||||
|
||||
### type
|
||||
@@ -3207,10 +3295,10 @@ Reference this group by using
|
||||
|
||||
| Property | Type | Required | Nullable | Defined by |
|
||||
| :-------------------------------------- | --------- | -------- | -------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [type](#type-37) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatechildtaskaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateChildTaskAction/properties/type") |
|
||||
| [type](#type-38) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatechildtaskaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateChildTaskAction/properties/type") |
|
||||
| [isNew](#isnew) | `boolean` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatechildtaskaction-properties-isnew.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateChildTaskAction/properties/isNew") |
|
||||
| [taskId](#taskid-2) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatechildtaskaction-properties-taskid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateChildTaskAction/properties/taskId") |
|
||||
| [categoryId](#categoryid-18) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatechildtaskaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateChildTaskAction/properties/categoryId") |
|
||||
| [categoryId](#categoryid-19) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatechildtaskaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateChildTaskAction/properties/categoryId") |
|
||||
| [taskTitle](#tasktitle) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatechildtaskaction-properties-tasktitle.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateChildTaskAction/properties/taskTitle") |
|
||||
| [extraTimeDuration](#extratimeduration) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatechildtaskaction-properties-extratimeduration.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateChildTaskAction/properties/extraTimeDuration") |
|
||||
|
||||
@@ -3328,7 +3416,7 @@ Reference this group by using
|
||||
|
||||
| Property | Type | Required | Nullable | Defined by |
|
||||
| :---------------------- | -------- | -------- | -------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [type](#type-38) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatedevicenameaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateDeviceNameAction/properties/type") |
|
||||
| [type](#type-39) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatedevicenameaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateDeviceNameAction/properties/type") |
|
||||
| [deviceId](#deviceid-7) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatedevicenameaction-properties-deviceid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateDeviceNameAction/properties/deviceId") |
|
||||
| [name](#name-1) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatedevicenameaction-properties-name.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateDeviceNameAction/properties/name") |
|
||||
|
||||
@@ -3398,7 +3486,7 @@ Reference this group by using
|
||||
|
||||
| Property | Type | Required | Nullable | Defined by |
|
||||
| :---------------------- | --------- | -------- | -------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [type](#type-39) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateenableactivitylevelblockingaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateEnableActivityLevelBlockingAction/properties/type") |
|
||||
| [type](#type-40) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateenableactivitylevelblockingaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateEnableActivityLevelBlockingAction/properties/type") |
|
||||
| [deviceId](#deviceid-8) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateenableactivitylevelblockingaction-properties-deviceid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateEnableActivityLevelBlockingAction/properties/deviceId") |
|
||||
| [enable](#enable-3) | `boolean` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateenableactivitylevelblockingaction-properties-enable.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateEnableActivityLevelBlockingAction/properties/enable") |
|
||||
|
||||
@@ -3468,7 +3556,7 @@ Reference this group by using
|
||||
|
||||
| Property | Type | Required | Nullable | Defined by |
|
||||
| :---------------------- | -------- | -------- | -------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [type](#type-40) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serialiizedupdatenetworktimeverificationaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerialiizedUpdateNetworkTimeVerificationAction/properties/type") |
|
||||
| [type](#type-41) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serialiizedupdatenetworktimeverificationaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerialiizedUpdateNetworkTimeVerificationAction/properties/type") |
|
||||
| [deviceId](#deviceid-9) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serialiizedupdatenetworktimeverificationaction-properties-deviceid.md "https://timelimit.io/SerializedParentAction#/definitions/SerialiizedUpdateNetworkTimeVerificationAction/properties/deviceId") |
|
||||
| [mode](#mode) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serialiizedupdatenetworktimeverificationaction-properties-mode.md "https://timelimit.io/SerializedParentAction#/definitions/SerialiizedUpdateNetworkTimeVerificationAction/properties/mode") |
|
||||
|
||||
@@ -3548,7 +3636,7 @@ Reference this group by using
|
||||
|
||||
| Property | Type | Required | Nullable | Defined by |
|
||||
| :-------------------- | --------- | -------- | -------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [type](#type-41) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateparentnotificationflagsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateParentNotificationFlagsAction/properties/type") |
|
||||
| [type](#type-42) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateparentnotificationflagsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateParentNotificationFlagsAction/properties/type") |
|
||||
| [parentId](#parentid) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateparentnotificationflagsaction-properties-parentid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateParentNotificationFlagsAction/properties/parentId") |
|
||||
| [flags](#flags-1) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateparentnotificationflagsaction-properties-flags.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateParentNotificationFlagsAction/properties/flags") |
|
||||
| [set](#set) | `boolean` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateparentnotificationflagsaction-properties-set.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateParentNotificationFlagsAction/properties/set") |
|
||||
@@ -3635,7 +3723,7 @@ Reference this group by using
|
||||
|
||||
| Property | Type | Required | Nullable | Defined by |
|
||||
| :------------------------ | --------- | -------- | -------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [type](#type-42) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatetimelimitruleaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateTimelimitRuleAction/properties/type") |
|
||||
| [type](#type-43) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatetimelimitruleaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateTimelimitRuleAction/properties/type") |
|
||||
| [ruleId](#ruleid-2) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatetimelimitruleaction-properties-ruleid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateTimelimitRuleAction/properties/ruleId") |
|
||||
| [time](#time-3) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatetimelimitruleaction-properties-time.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateTimelimitRuleAction/properties/time") |
|
||||
| [days](#days-1) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatetimelimitruleaction-properties-days.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateTimelimitRuleAction/properties/days") |
|
||||
@@ -3822,12 +3910,12 @@ Reference this group by using
|
||||
{"$ref":"https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserFlagsAction"}
|
||||
```
|
||||
|
||||
| Property | Type | Required | Nullable | Defined by |
|
||||
| :-------------------- | -------- | -------- | -------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [type](#type-43) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserflagsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserFlagsAction/properties/type") |
|
||||
| [userId](#userid-6) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserflagsaction-properties-userid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserFlagsAction/properties/userId") |
|
||||
| [modified](#modified) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserflagsaction-properties-modified.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserFlagsAction/properties/modified") |
|
||||
| [values](#values) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserflagsaction-properties-values.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserFlagsAction/properties/values") |
|
||||
| Property | Type | Required | Nullable | Defined by |
|
||||
| :---------------------- | -------- | -------- | -------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [type](#type-44) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserflagsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserFlagsAction/properties/type") |
|
||||
| [userId](#userid-6) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserflagsaction-properties-userid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserFlagsAction/properties/userId") |
|
||||
| [modified](#modified-1) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserflagsaction-properties-modified.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserFlagsAction/properties/modified") |
|
||||
| [values](#values-1) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserflagsaction-properties-values.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserFlagsAction/properties/values") |
|
||||
|
||||
### type
|
||||
|
||||
@@ -3911,9 +3999,9 @@ Reference this group by using
|
||||
|
||||
| Property | Type | Required | Nullable | Defined by |
|
||||
| :--------------------------- | -------- | -------- | -------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [type](#type-44) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserlimitlogincategory-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserLimitLoginCategory/properties/type") |
|
||||
| [type](#type-45) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserlimitlogincategory-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserLimitLoginCategory/properties/type") |
|
||||
| [userId](#userid-7) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserlimitlogincategory-properties-userid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserLimitLoginCategory/properties/userId") |
|
||||
| [categoryId](#categoryid-19) | `string` | Optional | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserlimitlogincategory-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserLimitLoginCategory/properties/categoryId") |
|
||||
| [categoryId](#categoryid-20) | `string` | Optional | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserlimitlogincategory-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserLimitLoginCategory/properties/categoryId") |
|
||||
|
||||
### type
|
||||
|
||||
@@ -3981,7 +4069,7 @@ Reference this group by using
|
||||
|
||||
| Property | Type | Required | Nullable | Defined by |
|
||||
| :------------------------------------ | -------- | -------- | -------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [type](#type-45) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserlimitloginpreblockduration-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserLimitLoginPreBlockDuration/properties/type") |
|
||||
| [type](#type-46) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserlimitloginpreblockduration-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserLimitLoginPreBlockDuration/properties/type") |
|
||||
| [userId](#userid-8) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserlimitloginpreblockduration-properties-userid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserLimitLoginPreBlockDuration/properties/userId") |
|
||||
| [preBlockDuration](#preblockduration) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserlimitloginpreblockduration-properties-preblockduration.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserLimitLoginPreBlockDuration/properties/preBlockDuration") |
|
||||
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
# Untitled number in ServerDataStatus Schema
|
||||
|
||||
```txt
|
||||
https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryBaseData/properties/flags
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
|
||||
| :------------------ | ---------- | -------------- | ----------------------- | :---------------- | --------------------- | ------------------- | ------------------------------------------------------------------------------------- |
|
||||
| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [ServerDataStatus.schema.json\*](ServerDataStatus.schema.json "open original schema") |
|
||||
|
||||
## flags Type
|
||||
|
||||
`number`
|
||||
@@ -36,6 +36,7 @@ https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryBaseData
|
||||
| [sort](#sort) | `number` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serverupdatedcategorybasedata-properties-sort.md "https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryBaseData/properties/sort") |
|
||||
| [networks](#networks) | `array` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serverupdatedcategorybasedata-properties-networks.md "https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryBaseData/properties/networks") |
|
||||
| [dlu](#dlu) | `number` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serverupdatedcategorybasedata-properties-dlu.md "https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryBaseData/properties/dlu") |
|
||||
| [flags](#flags) | `number` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serverupdatedcategorybasedata-properties-flags.md "https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryBaseData/properties/flags") |
|
||||
|
||||
## categoryId
|
||||
|
||||
@@ -308,3 +309,19 @@ https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryBaseData
|
||||
### dlu Type
|
||||
|
||||
`number`
|
||||
|
||||
## flags
|
||||
|
||||
|
||||
|
||||
|
||||
`flags`
|
||||
|
||||
- is required
|
||||
- Type: `number`
|
||||
- cannot be null
|
||||
- defined in: [ServerDataStatus](serverdatastatus-definitions-serverupdatedcategorybasedata-properties-flags.md "https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryBaseData/properties/flags")
|
||||
|
||||
### flags Type
|
||||
|
||||
`number`
|
||||
|
||||
@@ -1168,6 +1168,7 @@ Reference this group by using
|
||||
| [sort](#sort) | `number` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serverupdatedcategorybasedata-properties-sort.md "https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryBaseData/properties/sort") |
|
||||
| [networks](#networks) | `array` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serverupdatedcategorybasedata-properties-networks.md "https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryBaseData/properties/networks") |
|
||||
| [dlu](#dlu) | `number` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serverupdatedcategorybasedata-properties-dlu.md "https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryBaseData/properties/dlu") |
|
||||
| [flags](#flags) | `number` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serverupdatedcategorybasedata-properties-flags.md "https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryBaseData/properties/flags") |
|
||||
|
||||
### categoryId
|
||||
|
||||
@@ -1441,6 +1442,22 @@ Reference this group by using
|
||||
|
||||
`number`
|
||||
|
||||
### flags
|
||||
|
||||
|
||||
|
||||
|
||||
`flags`
|
||||
|
||||
- is required
|
||||
- Type: `number`
|
||||
- cannot be null
|
||||
- defined in: [ServerDataStatus](serverdatastatus-definitions-serverupdatedcategorybasedata-properties-flags.md "https://timelimit.io/ServerDataStatus#/definitions/ServerUpdatedCategoryBaseData/properties/flags")
|
||||
|
||||
#### flags Type
|
||||
|
||||
`number`
|
||||
|
||||
## Definitions group ServerCategoryNetworkId
|
||||
|
||||
Reference this group by using
|
||||
@@ -2273,7 +2290,7 @@ Reference this group by using
|
||||
| [relaxPrimaryDevice](#relaxprimarydevice) | `boolean` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serveruserentry-properties-relaxprimarydevice.md "https://timelimit.io/ServerDataStatus#/definitions/ServerUserEntry/properties/relaxPrimaryDevice") |
|
||||
| [mailNotificationFlags](#mailnotificationflags) | `number` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serveruserentry-properties-mailnotificationflags.md "https://timelimit.io/ServerDataStatus#/definitions/ServerUserEntry/properties/mailNotificationFlags") |
|
||||
| [blockedTimes](#blockedtimes-1) | `string` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serveruserentry-properties-blockedtimes.md "https://timelimit.io/ServerDataStatus#/definitions/ServerUserEntry/properties/blockedTimes") |
|
||||
| [flags](#flags) | `number` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serveruserentry-properties-flags.md "https://timelimit.io/ServerDataStatus#/definitions/ServerUserEntry/properties/flags") |
|
||||
| [flags](#flags-1) | `number` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serveruserentry-properties-flags.md "https://timelimit.io/ServerDataStatus#/definitions/ServerUserEntry/properties/flags") |
|
||||
| [llc](#llc) | `string` | Optional | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serveruserentry-properties-llc.md "https://timelimit.io/ServerDataStatus#/definitions/ServerUserEntry/properties/llc") |
|
||||
| [pbd](#pbd) | `number` | Optional | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serveruserentry-properties-pbd.md "https://timelimit.io/ServerDataStatus#/definitions/ServerUserEntry/properties/pbd") |
|
||||
|
||||
|
||||
Generated
+145
-198
@@ -189,14 +189,14 @@
|
||||
}
|
||||
},
|
||||
"@babel/parser": {
|
||||
"version": "7.12.11",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz",
|
||||
"integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg=="
|
||||
"version": "7.13.10",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.10.tgz",
|
||||
"integrity": "sha512-0s7Mlrw9uTWkYua7xWr99Wpk2bnGa0ANleKfksYAES8LpWH4gW1OUr42vqKNf0us5UQNfru2wPqMqRITzq/SIQ=="
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.12.12",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz",
|
||||
"integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==",
|
||||
"version": "7.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz",
|
||||
"integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==",
|
||||
"requires": {
|
||||
"@babel/helper-validator-identifier": "7.12.11",
|
||||
"lodash": "4.17.20",
|
||||
@@ -667,11 +667,6 @@
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
|
||||
},
|
||||
"async-limiter": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
|
||||
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
@@ -695,7 +690,7 @@
|
||||
"resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz",
|
||||
"integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==",
|
||||
"requires": {
|
||||
"@babel/types": "7.12.12"
|
||||
"@babel/types": "7.13.0"
|
||||
}
|
||||
},
|
||||
"backo2": {
|
||||
@@ -715,9 +710,9 @@
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||
},
|
||||
"base64-arraybuffer": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
|
||||
"integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz",
|
||||
"integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI="
|
||||
},
|
||||
"base64id": {
|
||||
"version": "2.0.0",
|
||||
@@ -741,14 +736,6 @@
|
||||
"tweetnacl": "0.14.5"
|
||||
}
|
||||
},
|
||||
"better-assert": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
|
||||
"integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
|
||||
"requires": {
|
||||
"callsite": "1.0.0"
|
||||
}
|
||||
},
|
||||
"big.js": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/big.js/-/big.js-6.0.3.tgz",
|
||||
@@ -844,10 +831,14 @@
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
|
||||
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
|
||||
},
|
||||
"callsite": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
|
||||
"integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA="
|
||||
"call-bind": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
|
||||
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
|
||||
"requires": {
|
||||
"function-bind": "1.1.1",
|
||||
"get-intrinsic": "1.1.1"
|
||||
}
|
||||
},
|
||||
"caseless": {
|
||||
"version": "0.12.0",
|
||||
@@ -900,7 +891,7 @@
|
||||
"resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz",
|
||||
"integrity": "sha1-x84o821LzZdE5f/CxfzeHHMmH8A=",
|
||||
"requires": {
|
||||
"is-regex": "1.1.1"
|
||||
"is-regex": "1.1.2"
|
||||
}
|
||||
},
|
||||
"character-reference-invalid": {
|
||||
@@ -1041,6 +1032,11 @@
|
||||
"resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
|
||||
"integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E="
|
||||
},
|
||||
"component-emitter": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
|
||||
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
|
||||
},
|
||||
"component-inherit": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
|
||||
@@ -1069,8 +1065,8 @@
|
||||
"resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz",
|
||||
"integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==",
|
||||
"requires": {
|
||||
"@babel/parser": "7.12.11",
|
||||
"@babel/types": "7.12.12"
|
||||
"@babel/parser": "7.13.10",
|
||||
"@babel/types": "7.13.0"
|
||||
}
|
||||
},
|
||||
"content-disposition": {
|
||||
@@ -1352,92 +1348,74 @@
|
||||
"integrity": "sha512-bd/DFLAoJetvv7ar/KIpE3CNO8wEuyrt9Xuw6nSMiZ+Vrz/Q21BPsMHvARL2Wz6IKHKXgb+DWZqtRg1vql9cBg=="
|
||||
},
|
||||
"engine.io": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.4.0.tgz",
|
||||
"integrity": "sha512-XCyYVWzcHnK5cMz7G4VTu2W7zJS7SM1QkcelghyIk/FmobWBtXE7fwhBusEKvCSqc3bMh8fNFMlUkCKTFRxH2w==",
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.5.0.tgz",
|
||||
"integrity": "sha512-21HlvPUKaitDGE4GXNtQ7PLP0Sz4aWLddMPw2VTyFz1FVZqu/kZsJUO8WNpKuE/OCL7nkfRaOui2ZCJloGznGA==",
|
||||
"requires": {
|
||||
"accepts": "1.3.7",
|
||||
"base64id": "2.0.0",
|
||||
"cookie": "0.3.1",
|
||||
"cookie": "0.4.1",
|
||||
"debug": "4.1.1",
|
||||
"engine.io-parser": "2.2.0",
|
||||
"ws": "7.2.0"
|
||||
"engine.io-parser": "2.2.1",
|
||||
"ws": "7.4.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"cookie": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
|
||||
"integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
|
||||
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
"ms": "2.1.3"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"engine.io-client": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.0.tgz",
|
||||
"integrity": "sha512-a4J5QO2k99CM2a0b12IznnyQndoEvtA4UAldhGzKqnHf42I3Qs2W5SPnDvatZRcMaNZs4IevVicBPayxYt6FwA==",
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.1.tgz",
|
||||
"integrity": "sha512-oVu9kBkGbcggulyVF0kz6BV3ganqUeqXvD79WOFKa+11oK692w1NyFkuEj4xrkFRpZhn92QOqTk4RQq5LiBXbQ==",
|
||||
"requires": {
|
||||
"component-emitter": "1.2.1",
|
||||
"component-emitter": "1.3.0",
|
||||
"component-inherit": "0.0.3",
|
||||
"debug": "4.1.1",
|
||||
"engine.io-parser": "2.2.0",
|
||||
"debug": "3.1.0",
|
||||
"engine.io-parser": "2.2.1",
|
||||
"has-cors": "1.1.0",
|
||||
"indexof": "0.0.1",
|
||||
"parseqs": "0.0.5",
|
||||
"parseuri": "0.0.5",
|
||||
"ws": "6.1.4",
|
||||
"parseqs": "0.0.6",
|
||||
"parseuri": "0.0.6",
|
||||
"ws": "7.4.4",
|
||||
"xmlhttprequest-ssl": "1.5.5",
|
||||
"yeast": "0.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"component-emitter": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
|
||||
"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"ws": {
|
||||
"version": "6.1.4",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz",
|
||||
"integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==",
|
||||
"requires": {
|
||||
"async-limiter": "1.0.1"
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"engine.io-parser": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.0.tgz",
|
||||
"integrity": "sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==",
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz",
|
||||
"integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==",
|
||||
"requires": {
|
||||
"after": "0.8.2",
|
||||
"arraybuffer.slice": "0.0.7",
|
||||
"base64-arraybuffer": "0.1.5",
|
||||
"base64-arraybuffer": "0.1.4",
|
||||
"blob": "0.0.5",
|
||||
"has-binary2": "1.0.3"
|
||||
}
|
||||
@@ -1678,6 +1656,16 @@
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"dev": true
|
||||
},
|
||||
"get-intrinsic": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
|
||||
"integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
|
||||
"requires": {
|
||||
"function-bind": "1.1.1",
|
||||
"has": "1.0.3",
|
||||
"has-symbols": "1.0.2"
|
||||
}
|
||||
},
|
||||
"get-paths": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/get-paths/-/get-paths-0.0.7.tgz",
|
||||
@@ -1807,9 +1795,9 @@
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
|
||||
},
|
||||
"has-symbols": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
|
||||
"integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg=="
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
|
||||
"integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
|
||||
},
|
||||
"has-unicode": {
|
||||
"version": "2.0.1",
|
||||
@@ -2085,11 +2073,12 @@
|
||||
"integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="
|
||||
},
|
||||
"is-regex": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz",
|
||||
"integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==",
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz",
|
||||
"integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==",
|
||||
"requires": {
|
||||
"has-symbols": "1.0.1"
|
||||
"call-bind": "1.0.2",
|
||||
"has-symbols": "1.0.2"
|
||||
}
|
||||
},
|
||||
"is-typedarray": {
|
||||
@@ -2773,11 +2762,6 @@
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||
},
|
||||
"object-component": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
|
||||
"integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE="
|
||||
},
|
||||
"on-finished": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
||||
@@ -2882,20 +2866,14 @@
|
||||
}
|
||||
},
|
||||
"parseqs": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
|
||||
"integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
|
||||
"requires": {
|
||||
"better-assert": "1.0.2"
|
||||
}
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz",
|
||||
"integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w=="
|
||||
},
|
||||
"parseuri": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
|
||||
"integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
|
||||
"requires": {
|
||||
"better-assert": "1.0.2"
|
||||
}
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz",
|
||||
"integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow=="
|
||||
},
|
||||
"parseurl": {
|
||||
"version": "1.3.3",
|
||||
@@ -3062,7 +3040,7 @@
|
||||
"mailparser": "3.0.1",
|
||||
"nodemailer": "6.4.17",
|
||||
"open": "7.3.0",
|
||||
"pug": "3.0.0",
|
||||
"pug": "3.0.2",
|
||||
"uuid": "8.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -3109,17 +3087,17 @@
|
||||
}
|
||||
},
|
||||
"pug": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pug/-/pug-3.0.0.tgz",
|
||||
"integrity": "sha512-inmsJyFBSHZaiGLaguoFgJGViX0If6AcfcElimvwj9perqjDpUpw79UIEDZbWFmoGVidh08aoE+e8tVkjVJPCw==",
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pug/-/pug-3.0.2.tgz",
|
||||
"integrity": "sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==",
|
||||
"requires": {
|
||||
"pug-code-gen": "3.0.1",
|
||||
"pug-code-gen": "3.0.2",
|
||||
"pug-filters": "4.0.0",
|
||||
"pug-lexer": "5.0.0",
|
||||
"pug-lexer": "5.0.1",
|
||||
"pug-linker": "4.0.0",
|
||||
"pug-load": "3.0.0",
|
||||
"pug-parser": "6.0.0",
|
||||
"pug-runtime": "3.0.0",
|
||||
"pug-runtime": "3.0.1",
|
||||
"pug-strip-comments": "2.0.0"
|
||||
}
|
||||
},
|
||||
@@ -3130,20 +3108,20 @@
|
||||
"requires": {
|
||||
"constantinople": "4.0.1",
|
||||
"js-stringify": "1.0.2",
|
||||
"pug-runtime": "3.0.0"
|
||||
"pug-runtime": "3.0.1"
|
||||
}
|
||||
},
|
||||
"pug-code-gen": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.1.tgz",
|
||||
"integrity": "sha512-xJIGvmXTQlkJllq6hqxxjRWcay2F9CU69TuAuiVZgHK0afOhG5txrQOcZyaPHBvSWCU/QQOqEp5XCH94rRZpBQ==",
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.2.tgz",
|
||||
"integrity": "sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg==",
|
||||
"requires": {
|
||||
"constantinople": "4.0.1",
|
||||
"doctypes": "1.1.0",
|
||||
"js-stringify": "1.0.2",
|
||||
"pug-attrs": "3.0.0",
|
||||
"pug-error": "2.0.0",
|
||||
"pug-runtime": "3.0.0",
|
||||
"pug-runtime": "3.0.1",
|
||||
"void-elements": "3.1.0",
|
||||
"with": "7.0.2"
|
||||
}
|
||||
@@ -3162,13 +3140,13 @@
|
||||
"jstransformer": "1.0.0",
|
||||
"pug-error": "2.0.0",
|
||||
"pug-walk": "2.0.0",
|
||||
"resolve": "1.19.0"
|
||||
"resolve": "1.20.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"resolve": {
|
||||
"version": "1.19.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz",
|
||||
"integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==",
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
|
||||
"integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
|
||||
"requires": {
|
||||
"is-core-module": "2.2.0",
|
||||
"path-parse": "1.0.6"
|
||||
@@ -3177,9 +3155,9 @@
|
||||
}
|
||||
},
|
||||
"pug-lexer": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.0.tgz",
|
||||
"integrity": "sha512-52xMk8nNpuyQ/M2wjZBN5gXQLIylaGkAoTk5Y1pBhVqaopaoj8Z0iVzpbFZAqitL4RHNVDZRnJDsqEYe99Ti0A==",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz",
|
||||
"integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==",
|
||||
"requires": {
|
||||
"character-parser": "2.2.0",
|
||||
"is-expression": "4.0.0",
|
||||
@@ -3214,9 +3192,9 @@
|
||||
}
|
||||
},
|
||||
"pug-runtime": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.0.tgz",
|
||||
"integrity": "sha512-GoEPcmQNnaTsePEdVA05bDpY+Op5VLHKayg08AQiqJBWU/yIaywEYv7TetC5dEQS3fzBBoyb2InDcZEg3mPTIA=="
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz",
|
||||
"integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg=="
|
||||
},
|
||||
"pug-strip-comments": {
|
||||
"version": "2.0.0",
|
||||
@@ -3621,16 +3599,16 @@
|
||||
"integrity": "sha1-vQSN23TefRymkV+qSldXCzVQwtc="
|
||||
},
|
||||
"socket.io": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.3.0.tgz",
|
||||
"integrity": "sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg==",
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.4.1.tgz",
|
||||
"integrity": "sha512-Si18v0mMXGAqLqCVpTxBa8MGqriHGQh8ccEOhmsmNS3thNCGBwO8WGrwMibANsWtQQ5NStdZwHqZR3naJVFc3w==",
|
||||
"requires": {
|
||||
"debug": "4.1.1",
|
||||
"engine.io": "3.4.0",
|
||||
"engine.io": "3.5.0",
|
||||
"has-binary2": "1.0.3",
|
||||
"socket.io-adapter": "1.1.1",
|
||||
"socket.io-client": "2.3.0",
|
||||
"socket.io-parser": "3.4.0"
|
||||
"socket.io-adapter": "1.1.2",
|
||||
"socket.io-client": "2.4.0",
|
||||
"socket.io-parser": "3.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
@@ -3638,53 +3616,45 @@
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
"ms": "2.1.3"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"socket.io-adapter": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz",
|
||||
"integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs="
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz",
|
||||
"integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g=="
|
||||
},
|
||||
"socket.io-client": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.0.tgz",
|
||||
"integrity": "sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.4.0.tgz",
|
||||
"integrity": "sha512-M6xhnKQHuuZd4Ba9vltCLT9oa+YvTsP8j9NcEiLElfIg8KeYPyhWOes6x4t+LTAC8enQbE/995AdTem2uNyKKQ==",
|
||||
"requires": {
|
||||
"backo2": "1.0.2",
|
||||
"base64-arraybuffer": "0.1.5",
|
||||
"component-bind": "1.0.0",
|
||||
"component-emitter": "1.2.1",
|
||||
"debug": "4.1.1",
|
||||
"engine.io-client": "3.4.0",
|
||||
"component-emitter": "1.3.0",
|
||||
"debug": "3.1.0",
|
||||
"engine.io-client": "3.5.1",
|
||||
"has-binary2": "1.0.3",
|
||||
"has-cors": "1.1.0",
|
||||
"indexof": "0.0.1",
|
||||
"object-component": "0.0.3",
|
||||
"parseqs": "0.0.5",
|
||||
"parseuri": "0.0.5",
|
||||
"socket.io-parser": "3.3.0",
|
||||
"parseqs": "0.0.6",
|
||||
"parseuri": "0.0.6",
|
||||
"socket.io-parser": "3.3.2",
|
||||
"to-array": "0.1.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"component-emitter": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
|
||||
"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"isarray": {
|
||||
@@ -3692,42 +3662,22 @@
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
|
||||
"integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"socket.io-parser": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz",
|
||||
"integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==",
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.2.tgz",
|
||||
"integrity": "sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg==",
|
||||
"requires": {
|
||||
"component-emitter": "1.2.1",
|
||||
"component-emitter": "1.3.0",
|
||||
"debug": "3.1.0",
|
||||
"isarray": "2.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"socket.io-parser": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.0.tgz",
|
||||
"integrity": "sha512-/G/VOI+3DBp0+DJKW4KesGnQkQPFmUCbA/oO2QGT6CWxU7hLGWqU3tyuzeSK/dqcyeHsQg1vTe9jiZI8GU9SCQ==",
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.1.tgz",
|
||||
"integrity": "sha512-11hMgzL+WCLWf1uFtHSNvliI++tcRUWdoeYuwIl+Axvwy9z2gQM+7nJyN3STj1tLj5JyIUH8/gpDGxzAlDdi0A==",
|
||||
"requires": {
|
||||
"component-emitter": "1.2.1",
|
||||
"debug": "4.1.1",
|
||||
@@ -3744,7 +3694,7 @@
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
"ms": "2.1.3"
|
||||
}
|
||||
},
|
||||
"isarray": {
|
||||
@@ -3753,9 +3703,9 @@
|
||||
"integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -4425,8 +4375,8 @@
|
||||
"resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz",
|
||||
"integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==",
|
||||
"requires": {
|
||||
"@babel/parser": "7.12.11",
|
||||
"@babel/types": "7.12.12",
|
||||
"@babel/parser": "7.13.10",
|
||||
"@babel/types": "7.13.0",
|
||||
"assert-never": "1.2.1",
|
||||
"babel-walk": "3.0.0-canary-5"
|
||||
}
|
||||
@@ -4514,12 +4464,9 @@
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
},
|
||||
"ws": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.2.0.tgz",
|
||||
"integrity": "sha512-+SqNqFbwTm/0DC18KYzIsMTnEWpLwJsiasW/O17la4iDRRIO9uaHbvKiAS3AHgTiuuWerK/brj4O6MYZkei9xg==",
|
||||
"requires": {
|
||||
"async-limiter": "1.0.1"
|
||||
}
|
||||
"version": "7.4.4",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz",
|
||||
"integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw=="
|
||||
},
|
||||
"xmlhttprequest-ssl": {
|
||||
"version": "1.5.5",
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"start": "node ./build/index.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"test": "node scripts/test-launch-with-different-databases.js",
|
||||
"lint": "tslint --project .",
|
||||
"lint:fix": "tslint --project . --fix",
|
||||
"build": "npm run build:clean && npm run build:json && npm run build:ts && npm run lint && npm run build:doc",
|
||||
@@ -62,7 +62,7 @@
|
||||
"pg-hstore": "^2.3.3",
|
||||
"rate-limiter-flexible": "^2.1.15",
|
||||
"sequelize": "^6.3.5",
|
||||
"socket.io": "^2.3.0",
|
||||
"socket.io": "^2.4.1",
|
||||
"tokgen": "^1.0.0",
|
||||
"umzug": "^2.3.0"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -29,7 +29,6 @@ const types = [
|
||||
'CreateFamilyByMailTokenRequest',
|
||||
'SignIntoFamilyRequest',
|
||||
'RecoverParentPasswordRequest',
|
||||
'CanRecoverPasswordRequest',
|
||||
'RegisterChildDeviceRequest',
|
||||
'SerializedParentAction',
|
||||
'SerializedAppLogicAction',
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const { databaseLaunchers } = require('./util/database')
|
||||
const { startMainApp } = require('./util/mainapp.js')
|
||||
|
||||
// use export PATH="$PATH:/usr/lib/postgresql/11/bin"
|
||||
// if the postgres binaries are not in the path
|
||||
|
||||
async function main() {
|
||||
let log = ''
|
||||
|
||||
for (const launcher of databaseLaunchers) {
|
||||
const database = await launcher()
|
||||
|
||||
console.log('Test with ' + database.type)
|
||||
|
||||
try {
|
||||
const task = await startMainApp({
|
||||
DATABASE_URL: database.connectionUrl
|
||||
})
|
||||
|
||||
console.log('test successfull')
|
||||
log += 'Worked with ' + database.type + '\n'
|
||||
|
||||
task.shutdown()
|
||||
} catch (ex) {
|
||||
log += 'Failure with ' + database.type + '\n'
|
||||
console.warn('test failed', ex)
|
||||
}
|
||||
|
||||
database.shutdown()
|
||||
}
|
||||
|
||||
console.log('\nRESULTS\n\n' + log)
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
main().catch((ex) => {
|
||||
console.warn(ex)
|
||||
})
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const { resolve } = require('path')
|
||||
|
||||
const tempDir = resolve(__dirname, '../../../tempdb')
|
||||
|
||||
module.exports = { tempDir }
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const { startPostgres } = require('./postgres.js')
|
||||
const { startMariadb } = require('./mariadb.js')
|
||||
const { startSqlite } = require('./sqlite.js')
|
||||
|
||||
module.exports = {
|
||||
startPostgres,
|
||||
databaseLaunchers: [ startMariadb, startPostgres, startSqlite ]
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const { resolve } = require('path')
|
||||
const { spawn } = require('child_process')
|
||||
const { tempDir } = require('./helper.js')
|
||||
const { generateShortToken, generateToken } = require('../token.js')
|
||||
const { rimrafAsync, mkdirAsync, readFileAsync, writeFileAsync } = require('../filesystem.js')
|
||||
const { spawnAsync } = require('../process.js')
|
||||
const { sleep } = require('../sleep.js')
|
||||
|
||||
async function startMariadb() {
|
||||
try { await mkdirAsync(tempDir) } catch (ex) {/* ignore */}
|
||||
|
||||
const instanceDir = resolve(tempDir, generateShortToken())
|
||||
const dataDir = resolve(instanceDir, 'data')
|
||||
const socketPath = resolve(instanceDir, 'socket')
|
||||
|
||||
await rimrafAsync(instanceDir)
|
||||
await mkdirAsync(instanceDir); await mkdirAsync(dataDir)
|
||||
|
||||
await spawnAsync('mysql_install_db', ['--datadir=' + dataDir, '--user=' + process.env.USER], { stdio: 'inherit' })
|
||||
|
||||
const task = await spawn('mysqld_safe', ['--no-defaults', '--datadir=' + dataDir, '--socket=' + socketPath, '--skip-networking'], { stdio: 'inherit' })
|
||||
task.on('exit', () => rimrafAsync(instanceDir))
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const { status } = await spawnAsync('mysqladmin', ['ping', '-S', socketPath])
|
||||
|
||||
if (status === 0) break
|
||||
|
||||
await sleep(100)
|
||||
}
|
||||
|
||||
const database = generateShortToken()
|
||||
const username = generateShortToken()
|
||||
const password = generateToken()
|
||||
|
||||
const commands = [
|
||||
'CREATE DATABASE `' + database + '` DEFAULT CHARACTER SET `utf8mb4` COLLATE `utf8mb4_bin`',
|
||||
// all users of the system can see this password because it is passed as command
|
||||
// line parameter - don't do this for anything important
|
||||
'CREATE USER `' + username + '`@localhost IDENTIFIED BY \'' + password + '\'',
|
||||
'GRANT ALL PRIVILEGES ON `' + database + '`.* TO `' + username + '`@localhost'
|
||||
]
|
||||
|
||||
for (command of commands) {
|
||||
console.log(command)
|
||||
await spawnAsync('mysql', ['-S', socketPath, '-u', 'root', '-e', command], { stdio: 'inherit' })
|
||||
}
|
||||
|
||||
return {
|
||||
shutdown: () => {
|
||||
spawnAsync('mysql', ['-S', socketPath, '-u', 'root', '-e', 'SHUTDOWN;'], { stdio: 'inherit' }).catch((ex) => {
|
||||
console.warn(ex)
|
||||
})
|
||||
},
|
||||
socketPath,
|
||||
dataDir,
|
||||
database,
|
||||
username,
|
||||
password,
|
||||
connectionUrl: 'mariadb://' + username + ':' + password + '@localhost/' + database + '?socketPath=' + encodeURIComponent(socketPath),
|
||||
type: 'mariadb'
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { startMariadb }
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const { resolve } = require('path')
|
||||
const { spawn } = require('child_process')
|
||||
const { tempDir } = require('./helper.js')
|
||||
const { generateShortToken, generateToken } = require('../token.js')
|
||||
const { rimrafAsync, mkdirAsync, readFileAsync, writeFileAsync } = require('../filesystem.js')
|
||||
const { spawnAsync } = require('../process.js')
|
||||
const { sleep } = require('../sleep.js')
|
||||
|
||||
async function startPostgres() {
|
||||
try { await mkdirAsync(tempDir) } catch (ex) {/* ignore */}
|
||||
|
||||
const instanceDir = resolve(tempDir, generateShortToken())
|
||||
const dataDir = resolve(instanceDir, 'data')
|
||||
const socketDir = resolve(instanceDir, 'socket')
|
||||
|
||||
await rimrafAsync(instanceDir)
|
||||
await mkdirAsync(instanceDir); await mkdirAsync(dataDir); await mkdirAsync(socketDir)
|
||||
|
||||
await spawnAsync('initdb', ['--locale=en_US.UTF-8', '-E', ' UTF8', '-D', dataDir], { stdio: 'inherit' })
|
||||
|
||||
const configFilePath = resolve(dataDir, 'postgresql.conf')
|
||||
const configFileContent = (await readFileAsync(configFilePath)) + '\n'
|
||||
+ 'unix_socket_directories = \'' + socketDir + '\'' + '\n'
|
||||
+ 'listen_addresses = \'\' # do not listen using TCP'
|
||||
|
||||
await writeFileAsync(configFilePath, configFileContent)
|
||||
|
||||
const task = spawn('postgres', ['-D', dataDir], { stdio: 'inherit' })
|
||||
task.on('exit', () => rimrafAsync(instanceDir))
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const { status } = await spawnAsync('pg_isready', ['-h', socketDir])
|
||||
|
||||
if (status === 0) break
|
||||
|
||||
await sleep(100)
|
||||
}
|
||||
|
||||
const database = generateShortToken()
|
||||
const username = generateShortToken()
|
||||
const password = generateToken() // this database accepts anything
|
||||
|
||||
await spawnAsync('createuser', ['-h', socketDir, username], { stdio: 'inherit' })
|
||||
await spawnAsync('createdb', ['-h', socketDir, database], { stdio: 'inherit' })
|
||||
|
||||
return {
|
||||
shutdown: () => task.kill('SIGINT'),
|
||||
socketDir,
|
||||
dataDir,
|
||||
database,
|
||||
username,
|
||||
password,
|
||||
connectionUrl: 'postgres://' + username + ':' + password + '@localhost/' + database + '?host=' + encodeURIComponent(socketDir),
|
||||
type: 'postgres'
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { startPostgres }
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const { resolve } = require('path')
|
||||
const { spawn } = require('child_process')
|
||||
const { tempDir } = require('./helper.js')
|
||||
const { generateShortToken, generateToken } = require('../token.js')
|
||||
const { rimrafAsync, mkdirAsync, readFileAsync, writeFileAsync } = require('../filesystem.js')
|
||||
const { spawnAsync } = require('../process.js')
|
||||
const { sleep } = require('../sleep.js')
|
||||
|
||||
async function startSqlite() {
|
||||
try { await mkdirAsync(tempDir) } catch (ex) {/* ignore */}
|
||||
|
||||
const instanceDir = resolve(tempDir, generateShortToken())
|
||||
|
||||
await rimrafAsync(instanceDir)
|
||||
await mkdirAsync(instanceDir)
|
||||
|
||||
return {
|
||||
shutdown: () => rimrafAsync(instanceDir),
|
||||
instanceDir,
|
||||
connectionUrl: 'sqlite:///' + instanceDir + '/test.db',
|
||||
type: 'sqlite'
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { startSqlite }
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const rimraf = require('rimraf')
|
||||
const { mkdir, readFile, writeFile } = require('fs')
|
||||
|
||||
function mkdirAsync(path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
mkdir(path, (err) => {
|
||||
if (err) reject(err)
|
||||
else resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function rimrafAsync(path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
rimraf(path, (err) => {
|
||||
if (err) reject(err)
|
||||
else resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function readFileAsync(path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
readFile(path, (err, res) => {
|
||||
if (err) reject(err)
|
||||
else resolve(res)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function writeFileAsync(path, content) {
|
||||
return new Promise((resolve, reject) => {
|
||||
writeFile(path, content, (err) => {
|
||||
if (err) reject(err)
|
||||
else resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = { mkdirAsync, rimrafAsync, readFileAsync, writeFileAsync }
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const { spawn } = require('child_process')
|
||||
const { resolve } = require('path')
|
||||
|
||||
function startMainApp(env) {
|
||||
const initPath = resolve(__dirname, '../../build/index.js')
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const task = spawn('node', [initPath], {
|
||||
stdio: ['inherit', 'pipe', 'inherit'],
|
||||
env: { ...process.env, PORT: 0 /* random port */, ...env }
|
||||
})
|
||||
|
||||
task.on('exit', () => reject(new Error('task terminated too early')))
|
||||
task.on('error', (ex) => reject(ex))
|
||||
|
||||
task.stdout.on('data', (data) => {
|
||||
if (data.toString('utf8').split('\n').indexOf('ready') !== -1) resolve(task)
|
||||
|
||||
process.stdout.write(data)
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
reject(new Error('timeout'))
|
||||
|
||||
task.kill('SIGINT')
|
||||
}, 1000 * 30)
|
||||
}).then((task) => {
|
||||
return {
|
||||
shutdown: () => task.kill('SIGINT')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = { startMainApp }
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const { spawn } = require('child_process')
|
||||
|
||||
function spawnAsync(command, args, options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const task = spawn(command, args, options)
|
||||
|
||||
task.on('error', (ex) => reject(ex))
|
||||
task.on('exit', (status) => resolve({ status }))
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = { spawnAsync }
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
function sleep(delay) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => resolve(), delay)
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = { sleep }
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const TokenGenerator = require('tokgen')
|
||||
|
||||
const tokenGenerator = new TokenGenerator({
|
||||
length: 32,
|
||||
chars: 'a-zA-Z0-9'
|
||||
})
|
||||
|
||||
const shortTokenGenerator = new TokenGenerator({
|
||||
length: 8,
|
||||
chars: 'a-zA-Z0-9'
|
||||
})
|
||||
|
||||
function generateToken() { return tokenGenerator.generate() }
|
||||
function generateShortToken() { return shortTokenGenerator.generate() }
|
||||
|
||||
module.exports = { generateToken, generateShortToken }
|
||||
+2
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -58,6 +58,7 @@ export { UpdateCategoryBatteryLimitAction } from './updatecategorybatterylimit'
|
||||
export { UpdateCategoryBlockAllNotificationsAction } from './updatecategoryblockallnotifications'
|
||||
export { UpdateCategoryBlockedTimesAction } from './updatecategoryblockedtimes'
|
||||
export { UpdateCategoryDisableLimitsAction } from './updatecategorydisablelimits'
|
||||
export { UpdateCategoryFlagsAction } from './updatecategoryflags'
|
||||
export { UpdateCategorySortingAction } from './updatecategorysorting'
|
||||
export { UpdateCategoryTemporarilyBlockedAction } from './updatecategorytemporarilyblocked'
|
||||
export { UpdateCategoryTimeWarningsAction } from './updatecategorytimewarnings'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -50,6 +50,7 @@ import { SerializedUpdateCategoryBatteryLimitAction, UpdateCategoryBatteryLimitA
|
||||
import { SerializedUpdateCategoryBlockAllNotificationsAction, UpdateCategoryBlockAllNotificationsAction } from '../updatecategoryblockallnotifications'
|
||||
import { SerializedUpdateCategoryBlockedTimesAction, UpdateCategoryBlockedTimesAction } from '../updatecategoryblockedtimes'
|
||||
import { SerializedUpdatCategoryDisableLimitsAction, UpdateCategoryDisableLimitsAction } from '../updatecategorydisablelimits'
|
||||
import { SerializedUpdateCategoryFlagsAction, UpdateCategoryFlagsAction } from '../updatecategoryflags'
|
||||
import { SerializedUpdateCategorySortingAction, UpdateCategorySortingAction } from '../updatecategorysorting'
|
||||
import { SerializedUpdateCategoryTemporarilyBlockedAction, UpdateCategoryTemporarilyBlockedAction } from '../updatecategorytemporarilyblocked'
|
||||
import { SerializedUpdateCategoryTimeWarningsAction, UpdateCategoryTimeWarningsAction } from '../updatecategorytimewarnings'
|
||||
@@ -98,6 +99,7 @@ export type SerializedParentAction =
|
||||
SerializedUpdateCategoryBlockAllNotificationsAction |
|
||||
SerializedUpdateCategoryBlockedTimesAction |
|
||||
SerializedUpdatCategoryDisableLimitsAction |
|
||||
SerializedUpdateCategoryFlagsAction |
|
||||
SerializedUpdateCategorySortingAction |
|
||||
SerializedUpdateCategoryTemporarilyBlockedAction |
|
||||
SerializedUpdateCategoryTimeWarningsAction |
|
||||
@@ -179,6 +181,8 @@ export const parseParentAction = (action: SerializedParentAction): ParentAction
|
||||
return UpdateCategoryBlockedTimesAction.parse(action)
|
||||
} else if (action.type === 'UPDATE_CATEGORY_DISABLE_LIMITS') {
|
||||
return UpdateCategoryDisableLimitsAction.parse(action)
|
||||
} else if (action.type === 'UPDATE_CATEGORY_FLAGS') {
|
||||
return UpdateCategoryFlagsAction.parse(action)
|
||||
} else if (action.type === 'UPDATE_CATEGORY_SORTING') {
|
||||
return UpdateCategorySortingAction.parse(action)
|
||||
} else if (action.type === 'UPDATE_CATEGORY_TIME_WARNINGS') {
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { maxCategoryFlags } from '../database/category'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { InvalidActionParameterException } from './meta/exception'
|
||||
import { assertIdWithinFamily, assertSafeInteger } from './meta/util'
|
||||
|
||||
const actionType = 'UpdateCategoryFlagsAction'
|
||||
|
||||
export class UpdateCategoryFlagsAction extends ParentAction {
|
||||
readonly categoryId: string
|
||||
readonly modifiedBits: number
|
||||
readonly newValues: number
|
||||
|
||||
constructor ({ categoryId, modifiedBits, newValues }: {
|
||||
categoryId: string
|
||||
modifiedBits: number
|
||||
newValues: number
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
|
||||
assertSafeInteger({ actionType, field: 'modifiedBits', value: modifiedBits })
|
||||
assertSafeInteger({ actionType, field: 'newValues', value: newValues })
|
||||
|
||||
if ((modifiedBits | maxCategoryFlags) !== maxCategoryFlags || (modifiedBits | newValues) !== modifiedBits) {
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'flags are out of the valid range',
|
||||
dynamicMessage: 'flags are out of the valid range: ' + modifiedBits + ', ' + newValues
|
||||
})
|
||||
}
|
||||
|
||||
this.categoryId = categoryId
|
||||
this.modifiedBits = modifiedBits
|
||||
this.newValues = newValues
|
||||
}
|
||||
|
||||
static parse = ({ categoryId, modified, values }: SerializedUpdateCategoryFlagsAction) => (
|
||||
new UpdateCategoryFlagsAction({
|
||||
categoryId,
|
||||
modifiedBits: modified,
|
||||
newValues: values
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
export interface SerializedUpdateCategoryFlagsAction {
|
||||
type: 'UPDATE_CATEGORY_FLAGS'
|
||||
categoryId: string
|
||||
modified: number
|
||||
values: number
|
||||
}
|
||||
+2
-21
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -21,7 +21,6 @@ import { BadRequest, Forbidden, Unauthorized } from 'http-errors'
|
||||
import { config } from '../config'
|
||||
import { Database, Transaction } from '../database'
|
||||
import { removeDevice } from '../function/device/remove-device'
|
||||
import { canRecoverPassword } from '../function/parent/can-recover-password'
|
||||
import { createAddDeviceToken } from '../function/parent/create-add-device-token'
|
||||
import { createFamily } from '../function/parent/create-family'
|
||||
import { getStatusByMailToken } from '../function/parent/get-status-by-mail-address'
|
||||
@@ -30,7 +29,7 @@ import { recoverParentPassword } from '../function/parent/recover-parent-passwor
|
||||
import { signInIntoFamily } from '../function/parent/sign-in-into-family'
|
||||
import { WebsocketApi } from '../websocket'
|
||||
import {
|
||||
isCanRecoverPasswordRequest, isCreateFamilyByMailTokenRequest,
|
||||
isCreateFamilyByMailTokenRequest,
|
||||
isCreateRegisterDeviceTokenRequest, isLinkParentMailAddressRequest,
|
||||
isMailAuthTokenRequestBody, isRecoverParentPasswordRequest,
|
||||
isRemoveDeviceRequest, isSignIntoFamilyRequest
|
||||
@@ -113,24 +112,6 @@ export const createParentRouter = ({ database, websocket }: {database: Database,
|
||||
}
|
||||
})
|
||||
|
||||
router.post('/can-recover-password', json(), async (req, res, next) => {
|
||||
try {
|
||||
if (!isCanRecoverPasswordRequest(req.body)) {
|
||||
throw new BadRequest()
|
||||
}
|
||||
|
||||
const canRecover = await canRecoverPassword({
|
||||
database,
|
||||
parentUserId: req.body.parentUserId,
|
||||
mailAuthToken: req.body.mailAuthToken
|
||||
})
|
||||
|
||||
res.json({ canRecover })
|
||||
} catch (ex) {
|
||||
next(ex)
|
||||
}
|
||||
})
|
||||
|
||||
router.post('/recover-parent-password', json(), async (req, res, next) => {
|
||||
try {
|
||||
if (!isRecoverParentPasswordRequest(req.body)) {
|
||||
|
||||
+1
-6
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -82,11 +82,6 @@ export interface RecoverParentPasswordRequest {
|
||||
password: ParentPassword
|
||||
}
|
||||
|
||||
export interface CanRecoverPasswordRequest {
|
||||
mailAuthToken: string
|
||||
parentUserId: string
|
||||
}
|
||||
|
||||
export interface RegisterChildDeviceRequest {
|
||||
registerToken: string
|
||||
childDevice: NewDeviceInfo
|
||||
|
||||
+35
-19
@@ -1,5 +1,5 @@
|
||||
// tslint:disable
|
||||
import { ClientPushChangesRequest, ClientPullChangesRequest, MailAuthTokenRequestBody, CreateFamilyByMailTokenRequest, SignIntoFamilyRequest, RecoverParentPasswordRequest, CanRecoverPasswordRequest, RegisterChildDeviceRequest, SerializedParentAction, SerializedAppLogicAction, SerializedChildAction, CreateRegisterDeviceTokenRequest, CanDoPurchaseRequest, FinishPurchaseByGooglePlayRequest, LinkParentMailAddressRequest, UpdatePrimaryDeviceRequest, RemoveDeviceRequest, RequestWithAuthToken, SendMailLoginCodeRequest, SignInByMailCodeRequest } from './schema'
|
||||
import { ClientPushChangesRequest, ClientPullChangesRequest, MailAuthTokenRequestBody, CreateFamilyByMailTokenRequest, SignIntoFamilyRequest, RecoverParentPasswordRequest, RegisterChildDeviceRequest, SerializedParentAction, SerializedAppLogicAction, SerializedChildAction, CreateRegisterDeviceTokenRequest, CanDoPurchaseRequest, FinishPurchaseByGooglePlayRequest, LinkParentMailAddressRequest, UpdatePrimaryDeviceRequest, RemoveDeviceRequest, RequestWithAuthToken, SendMailLoginCodeRequest, SignInByMailCodeRequest } from './schema'
|
||||
import Ajv from 'ajv'
|
||||
const ajv = new Ajv()
|
||||
|
||||
@@ -995,6 +995,33 @@ const definitions = {
|
||||
"type"
|
||||
]
|
||||
},
|
||||
"SerializedUpdateCategoryFlagsAction": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"UPDATE_CATEGORY_FLAGS"
|
||||
]
|
||||
},
|
||||
"categoryId": {
|
||||
"type": "string"
|
||||
},
|
||||
"modified": {
|
||||
"type": "number"
|
||||
},
|
||||
"values": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"categoryId",
|
||||
"modified",
|
||||
"type",
|
||||
"values"
|
||||
]
|
||||
},
|
||||
"SerializedUpdateCategorySortingAction": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -2051,6 +2078,9 @@ const definitions = {
|
||||
},
|
||||
"dlu": {
|
||||
"type": "number"
|
||||
},
|
||||
"flags": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@@ -2062,6 +2092,7 @@ const definitions = {
|
||||
"dlu",
|
||||
"extraTime",
|
||||
"extraTimeDay",
|
||||
"flags",
|
||||
"mblCharging",
|
||||
"mblMobile",
|
||||
"networks",
|
||||
@@ -2545,24 +2576,6 @@ export const isRecoverParentPasswordRequest: (value: object) => value is Recover
|
||||
"definitions": definitions,
|
||||
"$schema": "http://json-schema.org/draft-07/schema#"
|
||||
})
|
||||
export const isCanRecoverPasswordRequest: (value: object) => value is CanRecoverPasswordRequest = ajv.compile({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"mailAuthToken": {
|
||||
"type": "string"
|
||||
},
|
||||
"parentUserId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"mailAuthToken",
|
||||
"parentUserId"
|
||||
],
|
||||
"definitions": definitions,
|
||||
"$schema": "http://json-schema.org/draft-07/schema#"
|
||||
})
|
||||
export const isRegisterChildDeviceRequest: (value: object) => value is RegisterChildDeviceRequest = ajv.compile({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -2686,6 +2699,9 @@ export const isSerializedParentAction: (value: object) => value is SerializedPar
|
||||
{
|
||||
"$ref": "#/definitions/SerializedUpdatCategoryDisableLimitsAction"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/SerializedUpdateCategoryFlagsAction"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/SerializedUpdateCategorySortingAction"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -22,6 +22,12 @@ import { SequelizeAttributes } from './types'
|
||||
|
||||
export const allowedTimeWarningFlags = 1 | 2 | 4 | 8 | 16
|
||||
|
||||
export const categoryFlags = {
|
||||
hasBlockedNetworkList: 1
|
||||
}
|
||||
|
||||
export const maxCategoryFlags = categoryFlags.hasBlockedNetworkList
|
||||
|
||||
export interface CategoryAttributesVersion1 {
|
||||
familyId: string
|
||||
categoryId: string
|
||||
@@ -73,10 +79,14 @@ export interface CategoryAttributesVersion10 {
|
||||
taskListVersion: string
|
||||
}
|
||||
|
||||
export interface CategoryAttributesVersion11 {
|
||||
flags: string
|
||||
}
|
||||
|
||||
export type CategoryAttributes = CategoryAttributesVersion1 & CategoryAttributesVersion2 &
|
||||
CategoryAttributesVersion3 & CategoryAttributesVersion4 & CategoryAttributesVersion5 &
|
||||
CategoryAttributesVersion6 & CategoryAttributesVersion7 & CategoryAttributesVersion8 &
|
||||
CategoryAttributesVersion9 & CategoryAttributesVersion10
|
||||
CategoryAttributesVersion9 & CategoryAttributesVersion10 & CategoryAttributesVersion11
|
||||
|
||||
export type CategoryModel = Sequelize.Model<CategoryAttributes> & CategoryAttributes
|
||||
export type CategoryModelStatic = typeof Sequelize.Model & {
|
||||
@@ -210,6 +220,18 @@ export const attributesVersion10: SequelizeAttributes<CategoryAttributesVersion1
|
||||
}
|
||||
}
|
||||
|
||||
export const attributesVersion11: SequelizeAttributes<CategoryAttributesVersion11> = {
|
||||
flags: {
|
||||
type: Sequelize.BIGINT,
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
validate: {
|
||||
min: 0,
|
||||
max: maxCategoryFlags
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const attributes: SequelizeAttributes<CategoryAttributes> = {
|
||||
...attributesVersion1,
|
||||
...attributesVersion2,
|
||||
@@ -220,7 +242,8 @@ export const attributes: SequelizeAttributes<CategoryAttributes> = {
|
||||
...attributesVersion7,
|
||||
...attributesVersion8,
|
||||
...attributesVersion9,
|
||||
...attributesVersion10
|
||||
...attributesVersion10,
|
||||
...attributesVersion11
|
||||
}
|
||||
|
||||
export const createCategoryModel = (sequelize: Sequelize.Sequelize): CategoryModelStatic => sequelize.define('Category', attributes) as CategoryModelStatic
|
||||
|
||||
@@ -47,5 +47,6 @@ export const createConfigModel = (sequelize: Sequelize.Sequelize): ConfigModelSt
|
||||
|
||||
export const configItemIds = {
|
||||
statusMessage: 'status_message',
|
||||
selfTestData: 'self_test_data'
|
||||
selfTestData: 'self_test_data',
|
||||
secondSelfTestData: 'self_test_data_two'
|
||||
}
|
||||
|
||||
+4
-128
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -15,130 +15,6 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import * as Sequelize from 'sequelize'
|
||||
import { generateIdWithinFamily } from '../util/token'
|
||||
import { AddDeviceTokenModelStatic, createAddDeviceTokenModel } from './adddevicetoken'
|
||||
import { AppModelStatic, createAppModel } from './app'
|
||||
import { AppActivityModelStatic, createAppActivityModel } from './appactivity'
|
||||
import { AuthTokenModelStatic, createAuthtokenModel } from './authtoken'
|
||||
import { CategoryModelStatic, createCategoryModel } from './category'
|
||||
import { CategoryAppModelStatic, createCategoryAppModel } from './categoryapp'
|
||||
import { CategoryNetworkIdModelStatic, createCategoryNetworkIdModel } from './categorynetworkid'
|
||||
import { ChildTaskModelStatic, createChildTaskModel } from './childtask'
|
||||
import { configItemIds, ConfigModelStatic, createConfigModel } from './config'
|
||||
import { createDeviceModel, DeviceModelStatic } from './device'
|
||||
import { createFamilyModel, FamilyModelStatic } from './family'
|
||||
import { createMailLoginTokenModel, MailLoginTokenModelStatic } from './maillogintoken'
|
||||
import { createUmzug } from './migration/umzug'
|
||||
import { createOldDeviceModel, OldDeviceModelStatic } from './olddevice'
|
||||
import { createPurchaseModel, PurchaseModelStatic } from './purchase'
|
||||
import { createSessionDurationModel, SessionDurationModelStatic } from './sessionduration'
|
||||
import { createTimelimitRuleModel, TimelimitRuleModelStatic } from './timelimitrule'
|
||||
import { createUsedTimeModel, UsedTimeModelStatic } from './usedtime'
|
||||
import { createUserModel, UserModelStatic } from './user'
|
||||
import { createUserLimitLoginCategoryModel, UserLimitLoginCategoryModelStatic } from './userlimitlogincategory'
|
||||
|
||||
export type Transaction = Sequelize.Transaction
|
||||
|
||||
export interface Database {
|
||||
addDeviceToken: AddDeviceTokenModelStatic
|
||||
authtoken: AuthTokenModelStatic
|
||||
app: AppModelStatic
|
||||
appActivity: AppActivityModelStatic
|
||||
category: CategoryModelStatic
|
||||
categoryApp: CategoryAppModelStatic
|
||||
categoryNetworkId: CategoryNetworkIdModelStatic
|
||||
childTask: ChildTaskModelStatic
|
||||
config: ConfigModelStatic
|
||||
device: DeviceModelStatic
|
||||
family: FamilyModelStatic
|
||||
mailLoginToken: MailLoginTokenModelStatic
|
||||
oldDevice: OldDeviceModelStatic
|
||||
purchase: PurchaseModelStatic
|
||||
sessionDuration: SessionDurationModelStatic
|
||||
timelimitRule: TimelimitRuleModelStatic
|
||||
usedTime: UsedTimeModelStatic
|
||||
user: UserModelStatic
|
||||
userLimitLoginCategory: UserLimitLoginCategoryModelStatic
|
||||
transaction: <T> (autoCallback: (t: Transaction) => Promise<T>, options?: { transaction: Transaction }) => Promise<T>
|
||||
dialect: string
|
||||
}
|
||||
|
||||
const createDatabase = (sequelize: Sequelize.Sequelize): Database => ({
|
||||
addDeviceToken: createAddDeviceTokenModel(sequelize),
|
||||
authtoken: createAuthtokenModel(sequelize),
|
||||
app: createAppModel(sequelize),
|
||||
appActivity: createAppActivityModel(sequelize),
|
||||
category: createCategoryModel(sequelize),
|
||||
categoryApp: createCategoryAppModel(sequelize),
|
||||
childTask: createChildTaskModel(sequelize),
|
||||
categoryNetworkId: createCategoryNetworkIdModel(sequelize),
|
||||
config: createConfigModel(sequelize),
|
||||
device: createDeviceModel(sequelize),
|
||||
family: createFamilyModel(sequelize),
|
||||
mailLoginToken: createMailLoginTokenModel(sequelize),
|
||||
oldDevice: createOldDeviceModel(sequelize),
|
||||
purchase: createPurchaseModel(sequelize),
|
||||
sessionDuration: createSessionDurationModel(sequelize),
|
||||
timelimitRule: createTimelimitRuleModel(sequelize),
|
||||
usedTime: createUsedTimeModel(sequelize),
|
||||
user: createUserModel(sequelize),
|
||||
userLimitLoginCategory: createUserLimitLoginCategoryModel(sequelize),
|
||||
transaction: <T> (autoCallback: (transaction: Transaction) => Promise<T>, options?: { transaction: Transaction }) => (sequelize.transaction({
|
||||
isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.READ_COMMITTED,
|
||||
transaction: options?.transaction
|
||||
}, autoCallback) as any) as Promise<T>,
|
||||
dialect: sequelize.getDialect()
|
||||
})
|
||||
|
||||
export const sequelize = new Sequelize.Sequelize(process.env.DATABASE_URL || 'sqlite://test.db', {
|
||||
define: {
|
||||
timestamps: false
|
||||
},
|
||||
logging: false
|
||||
})
|
||||
|
||||
export const defaultDatabase = createDatabase(sequelize)
|
||||
export const defaultUmzug = createUmzug(sequelize)
|
||||
|
||||
class NestedTransactionTestException extends Error {}
|
||||
class TestRollbackException extends NestedTransactionTestException {}
|
||||
class NestedTransactionsNotWorkingException extends NestedTransactionTestException { constructor () { super('NestedTransactionsNotWorkingException') } }
|
||||
class IllegalStateException extends NestedTransactionTestException {}
|
||||
|
||||
export async function assertNestedTransactionsAreWorking (database: Database) {
|
||||
const testValue = generateIdWithinFamily()
|
||||
|
||||
// clean up just for the case
|
||||
await database.config.destroy({ where: { id: configItemIds.selfTestData } })
|
||||
|
||||
await database.transaction(async (transaction) => {
|
||||
const readOne = await database.config.findOne({ where: { id: configItemIds.selfTestData }, transaction })
|
||||
|
||||
if (readOne) throw new IllegalStateException()
|
||||
|
||||
await database.transaction(async (transaction) => {
|
||||
await database.config.create({ id: configItemIds.selfTestData, value: testValue }, { transaction })
|
||||
|
||||
const readTwo = await database.config.findOne({ where: { id: configItemIds.selfTestData }, transaction })
|
||||
|
||||
if (readTwo?.value !== testValue) throw new IllegalStateException()
|
||||
|
||||
try {
|
||||
await database.transaction(async (transaction) => {
|
||||
await database.config.destroy({ where: { id: configItemIds.selfTestData }, transaction })
|
||||
|
||||
throw new TestRollbackException()
|
||||
}, { transaction })
|
||||
} catch (ex) {
|
||||
if (!(ex instanceof TestRollbackException)) throw ex
|
||||
}
|
||||
|
||||
const readThree = await database.config.findOne({ where: { id: configItemIds.selfTestData }, transaction })
|
||||
|
||||
if (readThree?.value !== testValue) throw new NestedTransactionsNotWorkingException()
|
||||
|
||||
await database.config.destroy({ where: { id: configItemIds.selfTestData }, transaction })
|
||||
}, { transaction })
|
||||
})
|
||||
}
|
||||
export { Transaction, Database, defaultDatabase, defaultUmzug } from './main'
|
||||
export { assertNestedTransactionsAreWorking } from './utils/nested-transactions'
|
||||
export { assertSerializeableTransactionsAreWorking, shouldRetryWithException } from './utils/serialized'
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import * as Sequelize from 'sequelize'
|
||||
import { AddDeviceTokenModelStatic, createAddDeviceTokenModel } from './adddevicetoken'
|
||||
import { AppModelStatic, createAppModel } from './app'
|
||||
import { AppActivityModelStatic, createAppActivityModel } from './appactivity'
|
||||
import { AuthTokenModelStatic, createAuthtokenModel } from './authtoken'
|
||||
import { CategoryModelStatic, createCategoryModel } from './category'
|
||||
import { CategoryAppModelStatic, createCategoryAppModel } from './categoryapp'
|
||||
import { CategoryNetworkIdModelStatic, createCategoryNetworkIdModel } from './categorynetworkid'
|
||||
import { ChildTaskModelStatic, createChildTaskModel } from './childtask'
|
||||
import { ConfigModelStatic, createConfigModel } from './config'
|
||||
import { createDeviceModel, DeviceModelStatic } from './device'
|
||||
import { createFamilyModel, FamilyModelStatic } from './family'
|
||||
import { createMailLoginTokenModel, MailLoginTokenModelStatic } from './maillogintoken'
|
||||
import { createUmzug } from './migration/umzug'
|
||||
import { createOldDeviceModel, OldDeviceModelStatic } from './olddevice'
|
||||
import { createPurchaseModel, PurchaseModelStatic } from './purchase'
|
||||
import { createSessionDurationModel, SessionDurationModelStatic } from './sessionduration'
|
||||
import { createTimelimitRuleModel, TimelimitRuleModelStatic } from './timelimitrule'
|
||||
import { createUsedTimeModel, UsedTimeModelStatic } from './usedtime'
|
||||
import { createUserModel, UserModelStatic } from './user'
|
||||
import { createUserLimitLoginCategoryModel, UserLimitLoginCategoryModelStatic } from './userlimitlogincategory'
|
||||
|
||||
export type Transaction = Sequelize.Transaction
|
||||
|
||||
export interface Database {
|
||||
addDeviceToken: AddDeviceTokenModelStatic
|
||||
authtoken: AuthTokenModelStatic
|
||||
app: AppModelStatic
|
||||
appActivity: AppActivityModelStatic
|
||||
category: CategoryModelStatic
|
||||
categoryApp: CategoryAppModelStatic
|
||||
categoryNetworkId: CategoryNetworkIdModelStatic
|
||||
childTask: ChildTaskModelStatic
|
||||
config: ConfigModelStatic
|
||||
device: DeviceModelStatic
|
||||
family: FamilyModelStatic
|
||||
mailLoginToken: MailLoginTokenModelStatic
|
||||
oldDevice: OldDeviceModelStatic
|
||||
purchase: PurchaseModelStatic
|
||||
sessionDuration: SessionDurationModelStatic
|
||||
timelimitRule: TimelimitRuleModelStatic
|
||||
usedTime: UsedTimeModelStatic
|
||||
user: UserModelStatic
|
||||
userLimitLoginCategory: UserLimitLoginCategoryModelStatic
|
||||
transaction: <T> (autoCallback: (t: Transaction) => Promise<T>, options?: { transaction: Transaction }) => Promise<T>
|
||||
dialect: string
|
||||
}
|
||||
|
||||
const createDatabase = (sequelize: Sequelize.Sequelize): Database => ({
|
||||
addDeviceToken: createAddDeviceTokenModel(sequelize),
|
||||
authtoken: createAuthtokenModel(sequelize),
|
||||
app: createAppModel(sequelize),
|
||||
appActivity: createAppActivityModel(sequelize),
|
||||
category: createCategoryModel(sequelize),
|
||||
categoryApp: createCategoryAppModel(sequelize),
|
||||
childTask: createChildTaskModel(sequelize),
|
||||
categoryNetworkId: createCategoryNetworkIdModel(sequelize),
|
||||
config: createConfigModel(sequelize),
|
||||
device: createDeviceModel(sequelize),
|
||||
family: createFamilyModel(sequelize),
|
||||
mailLoginToken: createMailLoginTokenModel(sequelize),
|
||||
oldDevice: createOldDeviceModel(sequelize),
|
||||
purchase: createPurchaseModel(sequelize),
|
||||
sessionDuration: createSessionDurationModel(sequelize),
|
||||
timelimitRule: createTimelimitRuleModel(sequelize),
|
||||
usedTime: createUsedTimeModel(sequelize),
|
||||
user: createUserModel(sequelize),
|
||||
userLimitLoginCategory: createUserLimitLoginCategoryModel(sequelize),
|
||||
transaction: <T> (autoCallback: (transaction: Transaction) => Promise<T>, options?: { transaction: Transaction }) => (sequelize.transaction({
|
||||
isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.SERIALIZABLE,
|
||||
transaction: options?.transaction
|
||||
}, autoCallback) as any) as Promise<T>,
|
||||
dialect: sequelize.getDialect()
|
||||
})
|
||||
|
||||
export const sequelize = new Sequelize.Sequelize(process.env.DATABASE_URL || 'sqlite://test.db', {
|
||||
define: {
|
||||
timestamps: false
|
||||
},
|
||||
logging: false
|
||||
})
|
||||
|
||||
export const defaultDatabase = createDatabase(sequelize)
|
||||
export const defaultUmzug = createUmzug(sequelize)
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -58,12 +58,24 @@ export async function up (queryInterface: QueryInterface, sequelize: Sequelize)
|
||||
...usedTimeAttributesVersion3
|
||||
}, { transaction })
|
||||
|
||||
await sequelize.query(`
|
||||
INSERT INTO UsedTimes (familyId, categoryId, dayOfEpoch, usedTime, lastUpdate, startMinuteOfDay, endMinuteOfDay)
|
||||
SELECT familyId, categoryId, dayOfEpoch, usedTime, lastUpdate,
|
||||
${MinuteOfDay.MIN} AS startMinuteOfDay, ${MinuteOfDay.MAX} AS endMinuteOfDay
|
||||
FROM UsedTimesOld
|
||||
`, { transaction })
|
||||
const dialect = sequelize.getDialect()
|
||||
const isMysql = dialect === 'mysql' || dialect === 'mariadb'
|
||||
|
||||
if (isMysql) {
|
||||
await sequelize.query(`
|
||||
INSERT INTO UsedTimes (familyId, categoryId, dayOfEpoch, usedTime, lastUpdate, startMinuteOfDay, endMinuteOfDay)
|
||||
SELECT familyId, categoryId, dayOfEpoch, usedTime, lastUpdate,
|
||||
${MinuteOfDay.MIN} AS startMinuteOfDay, ${MinuteOfDay.MAX} AS endMinuteOfDay
|
||||
FROM UsedTimesOld
|
||||
`, { transaction })
|
||||
} else {
|
||||
await sequelize.query(`
|
||||
INSERT INTO "UsedTimes" ("familyId", "categoryId", "dayOfEpoch", "usedTime", "lastUpdate", "startMinuteOfDay", "endMinuteOfDay")
|
||||
SELECT "familyId", "categoryId", "dayOfEpoch", "usedTime", "lastUpdate",
|
||||
${MinuteOfDay.MIN} AS "startMinuteOfDay", ${MinuteOfDay.MAX} AS "endMinuteOfDay"
|
||||
FROM "UsedTimesOld"
|
||||
`, { transaction })
|
||||
}
|
||||
|
||||
await queryInterface.dropTable('UsedTimesOld', { transaction })
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -25,11 +25,22 @@ export async function up (queryInterface: QueryInterface, sequelize: Sequelize)
|
||||
await queryInterface.renameTable('Purchases', 'PurchasesOld', { transaction })
|
||||
await queryInterface.createTable('Purchases', purchaseAttributes, { transaction })
|
||||
|
||||
await sequelize.query(`
|
||||
INSERT INTO Purchases (familyId, service, transactionId, type, loggedAt, previousFullVersionEndTime, newFullVersionEndTime)
|
||||
SELECT familyId, service, transactionId, type, 0 AS loggedAt, 0 AS previousFullVersionEndTime, loggedAt AS newFullVersionEndTime
|
||||
FROM PurchasesOld
|
||||
`, { transaction })
|
||||
const dialect = sequelize.getDialect()
|
||||
const isMysql = dialect === 'mysql' || dialect === 'mariadb'
|
||||
|
||||
if (isMysql) {
|
||||
await sequelize.query(`
|
||||
INSERT INTO Purchases (familyId, service, transactionId, type, loggedAt, previousFullVersionEndTime, newFullVersionEndTime)
|
||||
SELECT familyId, service, transactionId, type, 0 AS loggedAt, 0 AS previousFullVersionEndTime, loggedAt AS newFullVersionEndTime
|
||||
FROM PurchasesOld
|
||||
`, { transaction })
|
||||
} else {
|
||||
await sequelize.query(`
|
||||
INSERT INTO "Purchases" ("familyId", service, "transactionId", type, "loggedAt", "previousFullVersionEndTime", "newFullVersionEndTime")
|
||||
SELECT "familyId", service, "transactionId", type, 0 AS "loggedAt", 0 AS "previousFullVersionEndTime", "loggedAt" AS "newFullVersionEndTime"
|
||||
FROM "PurchasesOld"
|
||||
`, { transaction })
|
||||
}
|
||||
|
||||
await queryInterface.dropTable('PurchasesOld', { transaction })
|
||||
})
|
||||
|
||||
+22
-8
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -21,14 +21,28 @@ export async function up (queryInterface: QueryInterface, sequelize: Sequelize)
|
||||
await sequelize.transaction({
|
||||
type: Transaction.TYPES.EXCLUSIVE
|
||||
}, async (transaction) => {
|
||||
await sequelize.query(
|
||||
'CREATE TABLE `UserLimitLoginCategories`' +
|
||||
'(`familyId` VARCHAR(10) NOT NULL, `userId` VARCHAR(6) NOT NULL, `categoryId` VARCHAR(6) NOT NULL,' +
|
||||
'PRIMARY KEY(`familyId`, `userId`), FOREIGN KEY(`familyId`, `userId`) REFERENCES `Users`(`familyId`, `userId`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`familyId`, `categoryId`) REFERENCES `Categories`(`familyId`, `categoryId`) ON UPDATE CASCADE ON DELETE CASCADE )',
|
||||
{ transaction }
|
||||
)
|
||||
const dialect = sequelize.getDialect()
|
||||
const isMysql = dialect === 'mysql' || dialect === 'mariadb'
|
||||
|
||||
await sequelize.query('CREATE INDEX `UserLimitLoginCategoriesIndexCategoryId` ON `UserLimitLoginCategories` (`familyId`, `categoryId`)', { transaction })
|
||||
if (isMysql) {
|
||||
await sequelize.query(
|
||||
'CREATE TABLE `UserLimitLoginCategories`' +
|
||||
'(`familyId` VARCHAR(10) NOT NULL, `userId` VARCHAR(6) NOT NULL, `categoryId` VARCHAR(6) NOT NULL,' +
|
||||
'PRIMARY KEY(`familyId`, `userId`), FOREIGN KEY(`familyId`, `userId`) REFERENCES `Users`(`familyId`, `userId`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`familyId`, `categoryId`) REFERENCES `Categories`(`familyId`, `categoryId`) ON UPDATE CASCADE ON DELETE CASCADE )',
|
||||
{ transaction }
|
||||
)
|
||||
|
||||
await sequelize.query('CREATE INDEX `UserLimitLoginCategoriesIndexCategoryId` ON `UserLimitLoginCategories` (`familyId`, `categoryId`)', { transaction })
|
||||
} else {
|
||||
await sequelize.query(
|
||||
'CREATE TABLE "UserLimitLoginCategories"' +
|
||||
'("familyId" VARCHAR(10) NOT NULL, "userId" VARCHAR(6) NOT NULL, "categoryId" VARCHAR(6) NOT NULL,' +
|
||||
'PRIMARY KEY("familyId", "userId"), FOREIGN KEY("familyId", "userId") REFERENCES "Users" ("familyId", "userId") ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY("familyId", "categoryId") REFERENCES "Categories" ("familyId", "categoryId") ON UPDATE CASCADE ON DELETE CASCADE )',
|
||||
{ transaction }
|
||||
)
|
||||
|
||||
await sequelize.query('CREATE INDEX "UserLimitLoginCategoriesIndexCategoryId" ON "UserLimitLoginCategories" ("familyId", "categoryId")', { transaction })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -21,14 +21,28 @@ export async function up (_: QueryInterface, sequelize: Sequelize) {
|
||||
await sequelize.transaction({
|
||||
type: Transaction.TYPES.EXCLUSIVE
|
||||
}, async (transaction) => {
|
||||
await sequelize.query(
|
||||
'CREATE TABLE `CategoryNetworkIds` ' +
|
||||
'(`familyId` VARCHAR(10) NOT NULL, `categoryId` VARCHAR(6) NOT NULL,' +
|
||||
'`networkItemId` VARCHAR(6) NOT NULL, `hashedNetworkId` VARCHAR(8) NOT NULL,' +
|
||||
'PRIMARY KEY(`familyId`, `categoryId`, `networkItemId`), FOREIGN KEY(`familyId`, `categoryId`)' +
|
||||
'REFERENCES `Categories`(`familyId`, `categoryId`) ON UPDATE CASCADE ON DELETE CASCADE )',
|
||||
{ transaction }
|
||||
)
|
||||
const dialect = sequelize.getDialect()
|
||||
const isMysql = dialect === 'mysql' || dialect === 'mariadb'
|
||||
|
||||
if (isMysql) {
|
||||
await sequelize.query(
|
||||
'CREATE TABLE `CategoryNetworkIds` ' +
|
||||
'(`familyId` VARCHAR(10) NOT NULL, `categoryId` VARCHAR(6) NOT NULL,' +
|
||||
'`networkItemId` VARCHAR(6) NOT NULL, `hashedNetworkId` VARCHAR(8) NOT NULL,' +
|
||||
'PRIMARY KEY(`familyId`, `categoryId`, `networkItemId`), FOREIGN KEY(`familyId`, `categoryId`)' +
|
||||
'REFERENCES `Categories`(`familyId`, `categoryId`) ON UPDATE CASCADE ON DELETE CASCADE )',
|
||||
{ transaction }
|
||||
)
|
||||
} else {
|
||||
await sequelize.query(
|
||||
'CREATE TABLE "CategoryNetworkIds" ' +
|
||||
'("familyId" VARCHAR(10) NOT NULL, "categoryId" VARCHAR(6) NOT NULL,' +
|
||||
'"networkItemId" VARCHAR(6) NOT NULL, "hashedNetworkId" VARCHAR(8) NOT NULL,' +
|
||||
'PRIMARY KEY("familyId", "categoryId", "networkItemId"), FOREIGN KEY("familyId", "categoryId")' +
|
||||
'REFERENCES "Categories"("familyId", "categoryId") ON UPDATE CASCADE ON DELETE CASCADE )',
|
||||
{ transaction }
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -22,18 +22,36 @@ export async function up (queryInterface: QueryInterface, sequelize: Sequelize)
|
||||
await sequelize.transaction({
|
||||
type: Transaction.TYPES.EXCLUSIVE
|
||||
}, async (transaction) => {
|
||||
await sequelize.query(
|
||||
'CREATE TABLE `ChildTasks` (' +
|
||||
'`familyId` VARCHAR(10) NOT NULL, `taskId` VARCHAR(6) NOT NULL,' +
|
||||
'`categoryId` VARCHAR(6) NOT NULL, `taskTitle` VARCHAR(50) NOT NULL,' +
|
||||
'`extraTimeDuration` INTEGER NOT NULL, `pendingRequest` INTEGER NOT NULL,' +
|
||||
'`lastGrantTimestamp` LONG NOT NULL,' +
|
||||
'PRIMARY KEY(`familyId`, `taskId`),' +
|
||||
'FOREIGN KEY(`familyId`, `categoryId`) REFERENCES `Categories`(`familyId`, `categoryId`) ' +
|
||||
'ON UPDATE CASCADE ON DELETE CASCADE' +
|
||||
')',
|
||||
{ transaction }
|
||||
)
|
||||
const dialect = sequelize.getDialect()
|
||||
const isMysql = dialect === 'mysql' || dialect === 'mariadb'
|
||||
|
||||
if (isMysql) {
|
||||
await sequelize.query(
|
||||
'CREATE TABLE `ChildTasks` (' +
|
||||
'`familyId` VARCHAR(10) NOT NULL, `taskId` VARCHAR(6) NOT NULL,' +
|
||||
'`categoryId` VARCHAR(6) NOT NULL, `taskTitle` VARCHAR(50) NOT NULL,' +
|
||||
'`extraTimeDuration` INTEGER NOT NULL, `pendingRequest` INTEGER NOT NULL,' +
|
||||
'`lastGrantTimestamp` LONG NOT NULL,' +
|
||||
'PRIMARY KEY(`familyId`, `taskId`),' +
|
||||
'FOREIGN KEY(`familyId`, `categoryId`) REFERENCES `Categories`(`familyId`, `categoryId`) ' +
|
||||
'ON UPDATE CASCADE ON DELETE CASCADE' +
|
||||
')',
|
||||
{ transaction }
|
||||
)
|
||||
} else {
|
||||
await sequelize.query(
|
||||
'CREATE TABLE "ChildTasks" (' +
|
||||
'"familyId" VARCHAR(10) NOT NULL, "taskId" VARCHAR(6) NOT NULL,' +
|
||||
'"categoryId" VARCHAR(6) NOT NULL, "taskTitle" VARCHAR(50) NOT NULL,' +
|
||||
'"extraTimeDuration" INTEGER NOT NULL, "pendingRequest" INTEGER NOT NULL,' +
|
||||
'"lastGrantTimestamp" BIGINT NOT NULL,' +
|
||||
'PRIMARY KEY("familyId", "taskId"),' +
|
||||
'FOREIGN KEY("familyId", "categoryId") REFERENCES "Categories"("familyId", "categoryId") ' +
|
||||
'ON UPDATE CASCADE ON DELETE CASCADE' +
|
||||
')',
|
||||
{ transaction }
|
||||
)
|
||||
}
|
||||
|
||||
await queryInterface.addColumn('Categories', 'taskListVersion', {
|
||||
...categoryAttributes.taskListVersion
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { QueryInterface, Sequelize, Transaction } from 'sequelize'
|
||||
import { attributesVersion11 as categoryAttributes } from '../../category'
|
||||
|
||||
export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
|
||||
await sequelize.transaction({
|
||||
type: Transaction.TYPES.EXCLUSIVE
|
||||
}, async (transaction) => {
|
||||
await queryInterface.addColumn('Categories', 'flags', {
|
||||
...categoryAttributes.flags
|
||||
}, {
|
||||
transaction
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
|
||||
await sequelize.transaction({
|
||||
type: Transaction.TYPES.EXCLUSIVE
|
||||
}, async (transaction) => {
|
||||
await queryInterface.removeColumn('Categories', 'flags', { transaction })
|
||||
})
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -61,7 +61,7 @@ export const attributesVersion1: SequelizeAttributes<TimelimitRuleAttributesVers
|
||||
categoryId: { ...idWithinFamilyColumn },
|
||||
applyToExtraTimeUsage: { ...booleanColumn },
|
||||
dayMaskAsBitmask: {
|
||||
type: Sequelize.TINYINT,
|
||||
type: Sequelize.SMALLINT,
|
||||
allowNull: false,
|
||||
validate: {
|
||||
min: 0,
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { generateIdWithinFamily } from '../../util/token'
|
||||
import { configItemIds } from '../config'
|
||||
import { Database } from '../main'
|
||||
|
||||
class NestedTransactionTestException extends Error {}
|
||||
class TestRollbackException extends NestedTransactionTestException {}
|
||||
class NestedTransactionsNotWorkingException extends NestedTransactionTestException { constructor () { super('NestedTransactionsNotWorkingException') } }
|
||||
class IllegalStateException extends NestedTransactionTestException {}
|
||||
|
||||
export async function assertNestedTransactionsAreWorking (database: Database) {
|
||||
const testValue = generateIdWithinFamily()
|
||||
|
||||
// clean up just for the case
|
||||
await database.config.destroy({ where: { id: configItemIds.selfTestData } })
|
||||
|
||||
await database.transaction(async (transaction) => {
|
||||
const readOne = await database.config.findOne({ where: { id: configItemIds.selfTestData }, transaction })
|
||||
|
||||
if (readOne) throw new IllegalStateException()
|
||||
|
||||
await database.transaction(async (transaction) => {
|
||||
await database.config.create({ id: configItemIds.selfTestData, value: testValue }, { transaction })
|
||||
|
||||
const readTwo = await database.config.findOne({ where: { id: configItemIds.selfTestData }, transaction })
|
||||
|
||||
if (readTwo?.value !== testValue) throw new IllegalStateException()
|
||||
|
||||
try {
|
||||
await database.transaction(async (transaction) => {
|
||||
await database.config.destroy({ where: { id: configItemIds.selfTestData }, transaction })
|
||||
|
||||
throw new TestRollbackException()
|
||||
}, { transaction })
|
||||
} catch (ex) {
|
||||
if (!(ex instanceof TestRollbackException)) throw ex
|
||||
}
|
||||
|
||||
const readThree = await database.config.findOne({ where: { id: configItemIds.selfTestData }, transaction })
|
||||
|
||||
if (readThree?.value !== testValue) throw new NestedTransactionsNotWorkingException()
|
||||
|
||||
await database.config.destroy({ where: { id: configItemIds.selfTestData }, transaction })
|
||||
}, { transaction })
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import * as Sequelize from 'sequelize'
|
||||
import { configItemIds } from '../config'
|
||||
import { Database } from '../main'
|
||||
|
||||
export class SerializationFeatureCheckException extends Error {}
|
||||
|
||||
export function shouldRetryWithException (database: Database, e: any): boolean {
|
||||
if (e instanceof Sequelize.TimeoutError) return true
|
||||
|
||||
if (!(e instanceof Sequelize.DatabaseError)) return false
|
||||
|
||||
const parent = e.parent
|
||||
|
||||
if (database.dialect === 'sqlite') {
|
||||
if (parent.message.startsWith('SQLITE_BUSY:')) return true
|
||||
} else if (database.dialect === 'postgres') {
|
||||
// 40001 = serialization_failure
|
||||
if ((parent as any).code === '40001') return true
|
||||
// 40P01 = deadlock detected
|
||||
if ((parent as any).code === '40P01') return true
|
||||
} else if (database.dialect === 'mariadb') {
|
||||
const errno = (parent as any).errno
|
||||
|
||||
// ER_LOCK_DEADLOCK
|
||||
// Deadlock found when trying to get lock; try restarting transaction
|
||||
if (errno === 1213) return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
export async function assertSerializeableTransactionsAreWorking (database: Database) {
|
||||
// clean up just for the case
|
||||
await database.config.destroy({
|
||||
where: {
|
||||
id: {
|
||||
[Sequelize.Op.in]: [ configItemIds.selfTestData, configItemIds.secondSelfTestData ]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// insert specific data
|
||||
await database.config.bulkCreate([
|
||||
{
|
||||
id: configItemIds.selfTestData,
|
||||
value: '123'
|
||||
},
|
||||
{
|
||||
id: configItemIds.secondSelfTestData,
|
||||
value: '456'
|
||||
}
|
||||
])
|
||||
|
||||
try {
|
||||
// use two parallel transactions
|
||||
await database.transaction(async (transactionOne) => {
|
||||
await database.transaction(async (transactionTwo) => {
|
||||
await database.config.findAll({ transaction: transactionOne })
|
||||
await database.config.findAll({ transaction: transactionTwo })
|
||||
|
||||
await Promise.all([
|
||||
(async () => {
|
||||
await database.config.update({ value: 'c' }, { where: { id: configItemIds.selfTestData }, transaction: transactionOne })
|
||||
})(),
|
||||
(async () => {
|
||||
await database.config.update({ value: 'd' }, { where: { id: configItemIds.secondSelfTestData }, transaction: transactionTwo })
|
||||
})()
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
throw new SerializationFeatureCheckException()
|
||||
} catch (ex) {
|
||||
if (!shouldRetryWithException(database, ex)) {
|
||||
throw new SerializationFeatureCheckException()
|
||||
}
|
||||
}
|
||||
|
||||
// finish clean up
|
||||
await database.config.destroy({
|
||||
where: {
|
||||
id: {
|
||||
[Sequelize.Op.in]: [ configItemIds.selfTestData, configItemIds.secondSelfTestData ]
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Conflict, InternalServerError, Unauthorized } from 'http-errors'
|
||||
import * as Sequelize from 'sequelize'
|
||||
import { config } from '../../config'
|
||||
import { Database } from '../../database'
|
||||
import { generateVersionId } from '../../util/token'
|
||||
@@ -60,7 +59,6 @@ export const setPrimaryDevice = async ({ database, websocket, deviceAuthToken, c
|
||||
userId: deviceEntry.currentUserId
|
||||
},
|
||||
transaction,
|
||||
lock: Sequelize.Transaction.LOCK.UPDATE,
|
||||
attributes: ['currentDevice']
|
||||
})
|
||||
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Database } from '../../database'
|
||||
import { requireMailByAuthToken } from '../authentication'
|
||||
|
||||
export const canRecoverPassword = async ({ database, mailAuthToken, parentUserId }: {
|
||||
database: Database
|
||||
mailAuthToken: string
|
||||
parentUserId: string
|
||||
// no transaction here because this is directly called from an API endpoint
|
||||
}): Promise<boolean> => {
|
||||
return database.transaction(async (transaction) => {
|
||||
const mail = await requireMailByAuthToken({ mailAuthToken, database, transaction })
|
||||
|
||||
const entry = await database.user.findOne({
|
||||
where: {
|
||||
mail,
|
||||
userId: parentUserId,
|
||||
type: 'parent'
|
||||
},
|
||||
transaction
|
||||
})
|
||||
|
||||
return !!entry
|
||||
})
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Conflict, Unauthorized } from 'http-errors'
|
||||
import * as Sequelize from 'sequelize'
|
||||
import { Database } from '../../database'
|
||||
import { generateVersionId } from '../../util/token'
|
||||
import { WebsocketApi } from '../../websocket'
|
||||
@@ -65,8 +64,7 @@ export const linkMailAddress = async ({ mailAuthToken, deviceAuthToken, parentUs
|
||||
familyId,
|
||||
userId: parentUserId
|
||||
},
|
||||
transaction,
|
||||
lock: Sequelize.Transaction.LOCK.UPDATE
|
||||
transaction
|
||||
})
|
||||
|
||||
if (!parentEntry) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Conflict } from 'http-errors'
|
||||
import * as Sequelize from 'sequelize'
|
||||
import { Database, Transaction } from '../../database'
|
||||
import { notifyClientsAboutChangesDelayed } from '../../function/websocket'
|
||||
import { WebsocketApi } from '../../websocket'
|
||||
@@ -51,8 +50,7 @@ export const addPurchase = async ({ database, familyId, type, transactionId, web
|
||||
where: {
|
||||
familyId
|
||||
},
|
||||
transaction,
|
||||
lock: Sequelize.Transaction.LOCK.UPDATE
|
||||
transaction
|
||||
})
|
||||
|
||||
if (!familyEntry) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -15,10 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import * as Sequelize from 'sequelize'
|
||||
import { AddUsedTimeAction } from '../../../../action'
|
||||
import { MinuteOfDay } from '../../../../util/minuteofday'
|
||||
import { Cache } from '../cache'
|
||||
import { IllegalStateException } from '../exception/illegal-state'
|
||||
import { MissingCategoryException } from '../exception/missing-item'
|
||||
|
||||
export const getRoundedTimestamp = () => {
|
||||
@@ -65,17 +65,10 @@ export async function dispatchAddUsedTime ({ action, cache }: {
|
||||
currentExtraTime: number
|
||||
}) => {
|
||||
if (action.timeToAdd !== 0) {
|
||||
const maxOperator = cache.database.dialect === 'sqlite' ? 'MAX' : 'GREATEST'
|
||||
const minOperator = cache.database.dialect === 'sqlite' ? 'MIN' : 'LEAST'
|
||||
|
||||
// try to update first
|
||||
const [updatedRows] = await cache.database.usedTime.update({
|
||||
usedTime: Sequelize.literal(`${maxOperator}(0, ${minOperator}(usedTime + ${action.timeToAdd}, ${dayLengthInMs}))`) as any,
|
||||
lastUpdate: roundedTimestamp
|
||||
}, {
|
||||
const oldItem = await cache.database.usedTime.findOne({
|
||||
where: {
|
||||
familyId: cache.familyId,
|
||||
categoryId: categoryId,
|
||||
categoryId: action.categoryId,
|
||||
dayOfEpoch: action.dayOfEpoch,
|
||||
startMinuteOfDay: MinuteOfDay.MIN,
|
||||
endMinuteOfDay: MinuteOfDay.MAX
|
||||
@@ -83,13 +76,38 @@ export async function dispatchAddUsedTime ({ action, cache }: {
|
||||
transaction: cache.transaction
|
||||
})
|
||||
|
||||
// otherwise create
|
||||
if (updatedRows === 0) {
|
||||
if (oldItem) {
|
||||
const oldUsedTime = oldItem.usedTime
|
||||
const newUsedTime = Math.max(0, Math.min(oldUsedTime + action.timeToAdd, dayLengthInMs))
|
||||
|
||||
const oldLastUpdate = parseInt(oldItem.lastUpdate, 10)
|
||||
const newLastUpdate = parseInt(roundedTimestamp, 10)
|
||||
|
||||
if (oldUsedTime !== newUsedTime || oldLastUpdate !== newLastUpdate) {
|
||||
const [updatedRows] = await cache.database.usedTime.update({
|
||||
usedTime: newUsedTime,
|
||||
lastUpdate: newLastUpdate.toString(10)
|
||||
}, {
|
||||
where: {
|
||||
familyId: cache.familyId,
|
||||
categoryId: action.categoryId,
|
||||
dayOfEpoch: action.dayOfEpoch,
|
||||
startMinuteOfDay: MinuteOfDay.MIN,
|
||||
endMinuteOfDay: MinuteOfDay.MAX
|
||||
},
|
||||
transaction: cache.transaction
|
||||
})
|
||||
|
||||
if (updatedRows === 0) {
|
||||
throw new IllegalStateException({ staticMessage: 'could not update fetched row' })
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await cache.database.usedTime.create({
|
||||
familyId: cache.familyId,
|
||||
categoryId: categoryId,
|
||||
categoryId: action.categoryId,
|
||||
dayOfEpoch: action.dayOfEpoch,
|
||||
usedTime: Math.min(action.timeToAdd, dayLengthInMs),
|
||||
usedTime: Math.max(0, Math.min(action.timeToAdd, dayLengthInMs)),
|
||||
lastUpdate: roundedTimestamp,
|
||||
startMinuteOfDay: MinuteOfDay.MIN,
|
||||
endMinuteOfDay: MinuteOfDay.MAX
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -15,12 +15,11 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import * as Sequelize from 'sequelize'
|
||||
import { AddUsedTimeActionVersion2 } from '../../../../action'
|
||||
import { EventHandler } from '../../../../monitoring/eventhandler'
|
||||
import { MinuteOfDay } from '../../../../util/minuteofday'
|
||||
import { Cache } from '../cache'
|
||||
import { SourceDeviceNotFoundException } from '../exception/illegal-state'
|
||||
import { IllegalStateException, SourceDeviceNotFoundException } from '../exception/illegal-state'
|
||||
import { getRoundedTimestamp as getRoundedTimestampForUsedTime } from './addusedtime'
|
||||
|
||||
export const getRoundedTimestampForSessionDuration = () => {
|
||||
@@ -92,14 +91,7 @@ export async function dispatchAddUsedTimeVersion2 ({ deviceId, action, cache, ev
|
||||
const lengthInMinutes = (end - start) + 1
|
||||
const lengthInMs = lengthInMinutes * 1000 * 60
|
||||
|
||||
const maxOperator = cache.database.dialect === 'sqlite' ? 'MAX' : 'GREATEST'
|
||||
const minOperator = cache.database.dialect === 'sqlite' ? 'MIN' : 'LEAST'
|
||||
|
||||
// try to update first
|
||||
const [updatedRows] = await cache.database.usedTime.update({
|
||||
usedTime: Sequelize.literal(`${maxOperator}(0, ${minOperator}(usedTime + ${item.timeToAdd}, ${lengthInMs}))`) as any,
|
||||
lastUpdate: roundedTimestampForUsedTime
|
||||
}, {
|
||||
const oldItem = await cache.database.usedTime.findOne({
|
||||
where: {
|
||||
familyId: cache.familyId,
|
||||
categoryId: item.categoryId,
|
||||
@@ -110,13 +102,38 @@ export async function dispatchAddUsedTimeVersion2 ({ deviceId, action, cache, ev
|
||||
transaction: cache.transaction
|
||||
})
|
||||
|
||||
// otherwise create
|
||||
if (updatedRows === 0) {
|
||||
if (oldItem) {
|
||||
const oldUsedTime = oldItem.usedTime
|
||||
const newUsedTime = Math.max(0, Math.min(oldUsedTime + item.timeToAdd, lengthInMs))
|
||||
|
||||
const oldLastUpdate = parseInt(oldItem.lastUpdate, 10)
|
||||
const newLastUpdate = parseInt(roundedTimestampForUsedTime, 10)
|
||||
|
||||
if (oldUsedTime !== newUsedTime || oldLastUpdate !== newLastUpdate) {
|
||||
const [updatedRows] = await cache.database.usedTime.update({
|
||||
usedTime: newUsedTime,
|
||||
lastUpdate: newLastUpdate.toString(10)
|
||||
}, {
|
||||
where: {
|
||||
familyId: cache.familyId,
|
||||
categoryId: item.categoryId,
|
||||
dayOfEpoch: action.dayOfEpoch,
|
||||
startMinuteOfDay: start,
|
||||
endMinuteOfDay: end
|
||||
},
|
||||
transaction: cache.transaction
|
||||
})
|
||||
|
||||
if (updatedRows === 0) {
|
||||
throw new IllegalStateException({ staticMessage: 'could not update fetched row' })
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await cache.database.usedTime.create({
|
||||
familyId: cache.familyId,
|
||||
categoryId: item.categoryId,
|
||||
dayOfEpoch: action.dayOfEpoch,
|
||||
usedTime: Math.min(item.timeToAdd, lengthInMs),
|
||||
usedTime: Math.max(0, Math.min(item.timeToAdd, lengthInMs)),
|
||||
lastUpdate: roundedTimestampForUsedTime,
|
||||
startMinuteOfDay: start,
|
||||
endMinuteOfDay: end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -15,7 +15,6 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import * as Sequelize from 'sequelize'
|
||||
import { ChildChangePasswordAction } from '../../../../action'
|
||||
import { Cache } from '../cache'
|
||||
import { SourceUserNotFoundException } from '../exception/illegal-state'
|
||||
@@ -31,8 +30,7 @@ export const dispatchChildChangePassword = async ({ action, childUserId, cache }
|
||||
userId: childUserId,
|
||||
type: 'child'
|
||||
},
|
||||
transaction: cache.transaction,
|
||||
lock: Sequelize.Transaction.LOCK.UPDATE
|
||||
transaction: cache.transaction
|
||||
})
|
||||
|
||||
if (!childEntry) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -15,7 +15,6 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import * as Sequelize from 'sequelize'
|
||||
import { ChangeParentPasswordAction, InvalidChangeParentPasswordIntegrityException } from '../../../../action/changeparentpassword'
|
||||
import { Cache } from '../cache'
|
||||
import { ApplyActionException } from '../exception/index'
|
||||
@@ -31,8 +30,7 @@ export async function dispatchChangeParentPassword ({ action, cache }: {
|
||||
userId: action.parentUserId,
|
||||
type: 'parent'
|
||||
},
|
||||
transaction: cache.transaction,
|
||||
lock: Sequelize.Transaction.LOCK.UPDATE
|
||||
transaction: cache.transaction
|
||||
})
|
||||
|
||||
if (!parentEntry) {
|
||||
|
||||
@@ -79,7 +79,8 @@ export async function dispatchCreateCategory ({ action, cache, fromChildSelfLimi
|
||||
disableLimitsUntil: '0',
|
||||
taskListVersion: generateVersionId(),
|
||||
minBatteryCharging: 0,
|
||||
minBatteryMobile: 0
|
||||
minBatteryMobile: 0,
|
||||
flags: '0'
|
||||
}, { transaction: cache.transaction })
|
||||
|
||||
// update the cache
|
||||
|
||||
@@ -50,6 +50,7 @@ import {
|
||||
UpdateCategoryBlockAllNotificationsAction,
|
||||
UpdateCategoryBlockedTimesAction,
|
||||
UpdateCategoryDisableLimitsAction,
|
||||
UpdateCategoryFlagsAction,
|
||||
UpdateCategorySortingAction,
|
||||
UpdateCategoryTemporarilyBlockedAction,
|
||||
UpdateCategoryTimeWarningsAction,
|
||||
@@ -100,6 +101,7 @@ import { dispatchUpdateCategoryBatteryLimit } from './updatecategorybatterylimit
|
||||
import { dispatchUpdateCategoryBlockAllNotifications } from './updatecategoryblockallnotifications'
|
||||
import { dispatchUpdateCategoryBlockedTimes } from './updatecategoryblockedtimes'
|
||||
import { dispatchUpdateCategoryDisableLimits } from './updatecategorydisablelimits'
|
||||
import { dispatchUpdateCategoryFlagsAction } from './updatecategoryflags'
|
||||
import { dispatchUpdateCategorySorting } from './updatecategorysorting'
|
||||
import { dispatchUpdateCategoryTemporarilyBlocked } from './updatecategorytemporarilyblocked'
|
||||
import { dispatchUpdateCategoryTimeWarnings } from './updatecategorytimewarnings'
|
||||
@@ -178,6 +180,8 @@ export const dispatchParentAction = async ({ action, cache, parentUserId, source
|
||||
return dispatchSetUserTimezone({ action, cache })
|
||||
} else if (action instanceof UpdateCategoryBatteryLimitAction) {
|
||||
return dispatchUpdateCategoryBatteryLimit({ action, cache })
|
||||
} else if (action instanceof UpdateCategoryFlagsAction) {
|
||||
return dispatchUpdateCategoryFlagsAction({ action, cache })
|
||||
} else if (action instanceof UpdateCategorySortingAction) {
|
||||
return dispatchUpdateCategorySorting({ action, cache })
|
||||
} else if (action instanceof IncrementCategoryExtraTimeAction) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -106,8 +106,7 @@ export async function dispatchRemoveUser ({ action, cache, parentUserId }: {
|
||||
familyId: cache.familyId,
|
||||
childId: action.userId
|
||||
},
|
||||
transaction: cache.transaction,
|
||||
lock: Sequelize.Transaction.LOCK.UPDATE
|
||||
transaction: cache.transaction
|
||||
})
|
||||
|
||||
await cache.database.categoryApp.destroy({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -15,7 +15,6 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import * as Sequelize from 'sequelize'
|
||||
import { SetChildPasswordAction } from '../../../../action'
|
||||
import { Cache } from '../cache'
|
||||
import { MissingUserException } from '../exception/missing-item'
|
||||
@@ -30,8 +29,7 @@ export async function dispatchSetChildPassword ({ action, cache }: {
|
||||
userId: action.childUserId,
|
||||
type: 'child'
|
||||
},
|
||||
transaction: cache.transaction,
|
||||
lock: Sequelize.Transaction.LOCK.UPDATE
|
||||
transaction: cache.transaction
|
||||
})
|
||||
|
||||
if (!childEntry) {
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { UpdateCategoryFlagsAction } from '../../../../action'
|
||||
import { Cache } from '../cache'
|
||||
import { IllegalStateException } from '../exception/illegal-state'
|
||||
import { MissingCategoryException } from '../exception/missing-item'
|
||||
|
||||
export async function dispatchUpdateCategoryFlagsAction ({ action, cache }: {
|
||||
action: UpdateCategoryFlagsAction
|
||||
cache: Cache
|
||||
}) {
|
||||
const categoryEntry = await cache.database.category.findOne({
|
||||
where: {
|
||||
familyId: cache.familyId,
|
||||
categoryId: action.categoryId
|
||||
},
|
||||
transaction: cache.transaction
|
||||
})
|
||||
|
||||
if (!categoryEntry) {
|
||||
throw new MissingCategoryException()
|
||||
}
|
||||
|
||||
const oldFlags = parseInt(categoryEntry.flags, 10)
|
||||
|
||||
if (!Number.isSafeInteger(oldFlags)) {
|
||||
throw new IllegalStateException({ staticMessage: 'oldFlags is not a safe integer' })
|
||||
}
|
||||
|
||||
const newFlags = (oldFlags & ~action.modifiedBits) | action.newValues
|
||||
|
||||
categoryEntry.flags = newFlags.toString(10)
|
||||
|
||||
await categoryEntry.save({ transaction: cache.transaction })
|
||||
|
||||
cache.categoriesWithModifiedBaseData.add(action.categoryId)
|
||||
}
|
||||
@@ -18,7 +18,7 @@
|
||||
import { BadRequest } from 'http-errors'
|
||||
import { ClientPushChangesRequest } from '../../../api/schema'
|
||||
import { VisibleConnectedDevicesManager } from '../../../connected-devices'
|
||||
import { Database } from '../../../database'
|
||||
import { Database, shouldRetryWithException } from '../../../database'
|
||||
import { EventHandler } from '../../../monitoring/eventhandler'
|
||||
import { WebsocketApi } from '../../../websocket'
|
||||
import { notifyClientsAboutChangesDelayed } from '../../websocket'
|
||||
@@ -104,7 +104,11 @@ export const applyActionsFromDevice = async ({ database, request, websocket, con
|
||||
}
|
||||
})
|
||||
} catch (ex) {
|
||||
if (ex instanceof ApplyActionException) {
|
||||
if (shouldRetryWithException(ex, database)) {
|
||||
eventHandler.countEvent('applyActionsFromDevice got exception which should cause retry')
|
||||
|
||||
throw ex
|
||||
} else if (ex instanceof ApplyActionException) {
|
||||
eventHandler.countEvent('applyActionsFromDevice errorDispatchingAction:' + ex.staticMessage)
|
||||
} else {
|
||||
const stack = ex instanceof Error && ex.stack ? ex.stack.substring(0, 4096) : 'no stack'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -51,7 +51,8 @@ export async function getCategoryBaseDatas ({
|
||||
'minBatteryMobile',
|
||||
'temporarilyBlockedEndTime',
|
||||
'sort',
|
||||
'disableLimitsUntil'
|
||||
'disableLimitsUntil',
|
||||
'flags'
|
||||
],
|
||||
transaction
|
||||
})).map((item) => ({
|
||||
@@ -70,7 +71,8 @@ export async function getCategoryBaseDatas ({
|
||||
minBatteryMobile: item.minBatteryMobile,
|
||||
temporarilyBlockedEndTime: item.temporarilyBlockedEndTime,
|
||||
sort: item.sort,
|
||||
disableLimitsUntil: item.disableLimitsUntil
|
||||
disableLimitsUntil: item.disableLimitsUntil,
|
||||
flags: item.flags
|
||||
}))
|
||||
|
||||
const networkIdsForSyncing = (await database.categoryNetworkId.findAll({
|
||||
@@ -114,6 +116,7 @@ export async function getCategoryBaseDatas ({
|
||||
itemId: network.networkItemId,
|
||||
hashedNetworkId: network.hashedNetworkId
|
||||
})),
|
||||
dlu: parseInt(item.disableLimitsUntil, 10)
|
||||
dlu: parseInt(item.disableLimitsUntil, 10),
|
||||
flags: parseInt(item.flags, 10)
|
||||
}))
|
||||
}
|
||||
|
||||
+3
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -19,7 +19,7 @@ import { Server } from 'http'
|
||||
import { createApi } from './api'
|
||||
import { config } from './config'
|
||||
import { VisibleConnectedDevicesManager } from './connected-devices'
|
||||
import { assertNestedTransactionsAreWorking, defaultDatabase, defaultUmzug } from './database'
|
||||
import { assertNestedTransactionsAreWorking, assertSerializeableTransactionsAreWorking, defaultDatabase, defaultUmzug } from './database'
|
||||
import { EventHandler } from './monitoring/eventhandler'
|
||||
import { InMemoryEventHandler } from './monitoring/inmemoryeventhandler'
|
||||
import { createWebsocketHandler } from './websocket'
|
||||
@@ -31,6 +31,7 @@ async function main () {
|
||||
const eventHandler: EventHandler = new InMemoryEventHandler()
|
||||
|
||||
await assertNestedTransactionsAreWorking(database)
|
||||
await assertSerializeableTransactionsAreWorking(database)
|
||||
|
||||
const connectedDevicesManager = new VisibleConnectedDevicesManager({
|
||||
database
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -117,6 +117,7 @@ export interface ServerUpdatedCategoryBaseData {
|
||||
networks: Array<ServerCategoryNetworkId>
|
||||
// disable limits until
|
||||
dlu: number
|
||||
flags: number
|
||||
}
|
||||
|
||||
export interface ServerCategoryNetworkId {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2021 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -53,7 +53,6 @@ async function deleteDeprecatedPurchases ({ database, websocket }: {
|
||||
},
|
||||
attributes: ['familyId'],
|
||||
transaction,
|
||||
lock: Sequelize.Transaction.LOCK.UPDATE,
|
||||
limit: 100
|
||||
})).map((item) => item.familyId)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user