Compare commits

..

98 Commits

Author SHA1 Message Date
Johannes Zellner bce3d3f664 Use fqdn instead of location for naked domain apps 2018-03-09 10:17:01 +01:00
Girish Ramakrishnan 828d6f6cc8 Show the provider and format for caas 2018-03-09 00:40:55 -08:00
Girish Ramakrishnan 0a026cc143 Display caas as Managed Cloudron 2018-03-09 00:37:20 -08:00
Girish Ramakrishnan 3bc9a87933 Fix display of caas domain 2018-03-09 00:29:00 -08:00
Girish Ramakrishnan 769f9adc9d Update mail domain when domain is updated 2018-03-08 18:06:50 -08:00
Johannes Zellner b5f53d921e Replace app-request link to point to the new forum 2018-03-08 21:46:16 +01:00
Girish Ramakrishnan 105e9e7825 Use the new app update pattern 2018-03-06 21:30:42 -08:00
Girish Ramakrishnan c8cf050156 Keep it alphabetical 2018-03-05 10:28:22 -08:00
Girish Ramakrishnan b7baafbbe6 actions -> events
also make it all past tense
2018-03-05 10:17:44 -08:00
Girish Ramakrishnan 85dde71ec3 fix display of undefined id
remove id display altogether, it's not very interesting to see it
2018-03-05 10:09:06 -08:00
Girish Ramakrishnan 2970b086a3 Updates -> App Updates 2018-03-05 09:39:03 -08:00
Johannes Zellner 5910709008 Use the correct model attribute for appId in feedback form 2018-03-05 17:10:00 +01:00
Johannes Zellner 2b6ce4f813 Reduce feedback form options and add ability to specify failing app 2018-03-05 12:54:09 +01:00
Johannes Zellner 451c697fb7 Show email as fallback when a user has no username yet 2018-03-05 12:14:20 +01:00
Johannes Zellner 09149318b1 Better format the multiselect element 2018-03-05 12:10:17 +01:00
Johannes Zellner d2d8eb9485 Allow to select multiple actions in the eventlog filter 2018-03-05 12:03:02 +01:00
Johannes Zellner 91265613a9 Prettify eventlog source display 2018-03-02 19:21:24 +01:00
Johannes Zellner 31c414bbe1 Use more readable datetime tooltip format in activity log 2018-03-02 18:58:49 +01:00
Johannes Zellner e2a3654ed7 Give the time more space in the activity log 2018-03-02 18:50:49 +01:00
Johannes Zellner 96d7283534 Do not alternate the background color of the activity log 2018-03-02 18:50:32 +01:00
Girish Ramakrishnan 256a7e322b Keep it all to two words 2018-03-02 09:12:53 -08:00
Johannes Zellner e5b78337ac Show more readable user event data 2018-03-02 13:42:24 +01:00
Johannes Zellner 67ba5aa1c5 fix indentation 2018-03-02 13:19:57 +01:00
Johannes Zellner 848a617f98 Make eventlog entries expandable to show raw event data 2018-03-02 10:50:05 +01:00
Johannes Zellner 1fc7efef0d Improve app related eventlog display 2018-03-02 10:49:46 +01:00
Girish Ramakrishnan 576f6eafbb Rename Chat to Forum 2018-03-01 13:40:10 -08:00
Girish Ramakrishnan 2caf73b5e3 Do not list mail domains and aliases if username is not available 2018-02-28 15:21:42 -08:00
Girish Ramakrishnan 56abb68e0c Link admin link to docs 2018-02-28 13:40:06 -08:00
Girish Ramakrishnan 7aaac5a48a reword email address on domains 2018-02-28 13:26:15 -08:00
Girish Ramakrishnan 8326587886 Give indication that the test is for the relay 2018-02-27 09:24:36 -08:00
Girish Ramakrishnan 466b3f4784 Make the user edit dialog say "Primary email" 2018-02-24 16:42:15 -08:00
Girish Ramakrishnan bccdf548a8 Fix typo making the MX records hidden 2018-02-23 17:04:38 -08:00
Girish Ramakrishnan fa4b1b3d5b Add note that user and group mailboxes must be enabled 2018-02-23 17:02:18 -08:00
Girish Ramakrishnan 9d47fd198f replace chat with forum 2018-02-23 15:53:23 -08:00
Girish Ramakrishnan 5966ee6800 replace terms link with license 2018-02-23 15:25:27 -08:00
Johannes Zellner 2d20e3c13d Scroll to top on category activation 2018-02-23 11:34:39 -08:00
Johannes Zellner 2172f8532d Rework the appstore category list 2018-02-23 11:34:27 -08:00
Johannes Zellner 9dc4318152 Reduce category item size 2018-02-23 11:34:04 -08:00
Johannes Zellner e1a92e7127 Make primary email labels explicit 2018-02-23 10:29:09 -08:00
Girish Ramakrishnan 767b31caa2 Display the pretty domain provider name in the table
This is especially needed to distinguish wildcard/manual.
2018-02-21 10:14:17 -08:00
Johannes Zellner c2232936e0 Replace chat with forum in the support page 2018-02-20 11:55:57 -08:00
Johannes Zellner 4f1bbfd9e3 Make it clear that support ssh button should be enabled only if we ask the user to do so 2018-02-20 11:27:12 -08:00
Johannes Zellner caf57e37dc Add eventlog groups for apps and users 2018-02-20 11:13:51 -08:00
Johannes Zellner 64b8e4ad6c Shorten app ids in eventlog 2018-02-19 01:56:12 -08:00
Johannes Zellner c9d3907124 Add missing whitespace 2018-02-19 01:56:12 -08:00
Girish Ramakrishnan bf6bea800b Add note that user/group mailboxes must be enabled 2018-02-18 12:04:37 -08:00
Johannes Zellner 26f1673d47 Show full fqdn on app grid item hover 2018-02-17 16:01:36 -08:00
Johannes Zellner 08153454a2 Show tooltips immediately for app actions to guide the user 2018-02-09 10:11:23 +01:00
Girish Ramakrishnan efc26ab587 Specify which domain mail should be enabled for 2018-02-08 19:08:00 -08:00
Girish Ramakrishnan e24e0a7e87 br was removed by mistake in 23bc267c46 2018-02-08 15:25:37 -08:00
Johannes Zellner 23bc267c46 Show full fqdn in apps grid for now instead of the domain on the top 2018-02-08 16:17:47 +01:00
Johannes Zellner 35cc592d61 Remove altDomain ui bits 2018-02-08 09:44:35 +01:00
Girish Ramakrishnan 512f6a1166 Remove obsolete action 2018-02-06 23:14:37 -08:00
Johannes Zellner 3160ffec3f The update schedule is only set for the apps now 2018-02-06 19:39:06 +01:00
Johannes Zellner c543d4517f Adjust to new autoupdate pattern rest apis 2018-02-06 19:25:06 +01:00
Girish Ramakrishnan d7334b991b Add DO SGP1 2018-02-05 11:06:40 -08:00
Girish Ramakrishnan 2b355f6ee4 typo 2018-02-03 18:23:49 -08:00
Girish Ramakrishnan cd6af57a6e Use SOS ng endpoint and v4
https://www.exoscale.ch/syslog/2018/01/09/object-storage/
2018-02-02 16:29:10 -08:00
Girish Ramakrishnan 674028ee77 This probably explains why people ask for support in issue tracker 2018-02-02 11:39:36 -08:00
Girish Ramakrishnan f51c2e7b61 pass env=dev as search param to set the tlsConfig 2018-01-31 21:02:12 -08:00
Johannes Zellner 182085d3f8 Remove the generation of the splash screen assets 2018-01-31 09:23:42 +01:00
Johannes Zellner b8e70f1160 Remove console.log() 2018-01-30 17:01:27 +01:00
Johannes Zellner c624c04e9d Hide alias and mailling list UI when no domain has email enabled 2018-01-30 16:33:27 +01:00
Johannes Zellner 666badfa38 Mailinglist remove route returns 204 2018-01-30 13:38:25 +01:00
Girish Ramakrishnan 21b9843083 Enable selector for now 2018-01-29 19:33:56 -08:00
Girish Ramakrishnan f3b53a22f5 Remove use of config.fqdn 2018-01-29 14:35:47 -08:00
Girish Ramakrishnan f850235b3a Remove ununsed setAdminCertificate 2018-01-26 20:46:58 -08:00
Girish Ramakrishnan f555cfddd0 Uncomment for testing 2018-01-26 11:53:26 -08:00
Johannes Zellner 1c9052f085 Rework the email domain and alias handling for user edits to fix various bugs 2018-01-26 15:39:35 +01:00
Johannes Zellner 6a450b7190 setAlias returns 202 on success 2018-01-26 15:39:02 +01:00
Johannes Zellner 75194525fb Remove unused function showBubble() 2018-01-26 15:04:18 +01:00
Johannes Zellner 9d57c81505 Add group edit ui to select mailing lists 2018-01-26 11:31:43 +01:00
Johannes Zellner 8af587b6d9 Add mailing list api wrappers 2018-01-26 11:31:19 +01:00
Girish Ramakrishnan c1cb2eda00 Add a hack for now to just add/remove mail domains as part of domains API 2018-01-25 13:40:45 -08:00
Girish Ramakrishnan 90c867da82 Fix the text 2018-01-25 10:08:29 -08:00
Johannes Zellner d97268dfa7 Give some busy indicator while email configs are fetching 2018-01-25 18:28:11 +01:00
Johannes Zellner c3ce6ef9f0 Add alias ui in user edit 2018-01-25 18:17:40 +01:00
Johannes Zellner eb3d6fe5f1 Use the new alias api in api wrapper 2018-01-25 18:16:47 +01:00
Johannes Zellner e39e7d4898 Adjust to the mailboxes route name change 2018-01-25 12:28:39 +01:00
Johannes Zellner b282375ac7 Also allow to change the fallbackEmail for users 2018-01-24 16:21:14 +01:00
Johannes Zellner 8deb28f8eb Add multiselect to enable mailboxes per user and domain 2018-01-24 16:20:56 +01:00
Johannes Zellner e91833dcf2 Add mailbox api wrappers to client.js 2018-01-24 16:20:21 +01:00
Girish Ramakrishnan ca9781c279 Fix display of domain 2018-01-23 20:43:49 -08:00
Girish Ramakrishnan 2d8412a629 Make API Key text clearer 2018-01-23 18:15:48 -08:00
Girish Ramakrishnan e4b253da22 test email now requires a domain 2018-01-23 16:10:09 -08:00
Girish Ramakrishnan 6edad6b986 remove enterprise checks 2018-01-23 11:55:36 -08:00
Johannes Zellner 7b7e94d3d6 Not sure what to do yet with alias ui in users settings, so disable to make the ui itself work 2018-01-23 17:09:47 +01:00
Johannes Zellner bc164281db Always show warning if an app requires email to be enabled for the selected domain
We can be smarter in the future and show this based on currently
selected domain from the dropdown
2018-01-23 16:51:53 +01:00
Johannes Zellner f94380b2dd Disable multidomain for domains and email view 2018-01-23 15:37:55 +01:00
Johannes Zellner a2241a4e47 Fix return code for email toggle to let the UI correctly react 2018-01-23 15:35:02 +01:00
Johannes Zellner 7e5afcfe6a Reenable and provision the catchall dropdown 2018-01-23 15:11:33 +01:00
Johannes Zellner 7c926cc051 Already update the ui while checking the mail status 2018-01-23 12:41:52 +01:00
Johannes Zellner 16f43e3eac Fixup the status check logic 2018-01-23 12:38:19 +01:00
Johannes Zellner 456577a166 First round of mail view refactoring 2018-01-23 12:30:35 +01:00
Johannes Zellner 7166604fc0 Temporarily disable toplevel email check notification 2018-01-23 12:30:16 +01:00
Johannes Zellner 0ae8d1ed4d Refactor the mail related api wrappers 2018-01-23 12:29:57 +01:00
Girish Ramakrishnan 4388aee70d add dot files 2018-01-22 17:44:51 -08:00
Girish Ramakrishnan 13e4ceff44 Initial commit 2018-01-22 13:01:38 -08:00
551 changed files with 54598 additions and 59713 deletions
-29
View File
@@ -1,29 +0,0 @@
{
"env": {
"node": true,
"es6": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 8
},
"rules": {
"indent": [
"error",
4
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
],
"no-console": "off"
}
}
+1 -2
View File
@@ -1,7 +1,6 @@
# following files are skipped when exporting using git archive
test export-ignore
.jshintrc export-ignore
.gitlab export-ignore
docs export-ignore
.gitattributes export-ignore
.gitignore export-ignore
+1
View File
@@ -6,3 +6,4 @@ installer/src/certs/server.key
# vim swap files
*.swp
-6
View File
@@ -1,6 +0,0 @@
Please do not use this issue tracker for support requests and bug reports.
This issue tracker is used by the Cloudron development team to track actual
bugs in the code.
Please use the forum at https://forum.cloudron.io to report bugs. For
confidential issues, please email us at support@cloudron.io.
-7
View File
@@ -1,7 +0,0 @@
Please do not use this issue tracker for support requests and feature reports.
This issue tracker is used by the Cloudron development team to track issues in
the code.
Please use the forum at https://forum.cloudron.io to report bugs. For
confidential issues, please email us at support@cloudron.io.
+8
View File
@@ -0,0 +1,8 @@
{
"node": true,
"browser": true,
"unused": true,
"globalstrict": true,
"predef": [ "angular", "$" ],
"esnext": true
}
-1954
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,5 +1,5 @@
The Cloudron Subscription license
Copyright (c) 2020 Cloudron UG
Copyright (c) 2018 Cloudron UG
With regard to the Cloudron Software:
+17 -8
View File
@@ -37,19 +37,28 @@ anyone to effortlessly host web applications on their server on their own terms.
## Demo
Try our demo at https://my.demo.cloudron.io (username: cloudron password: cloudron).
Try our demo at https://my-demo.cloudron.me (username: cloudron password: cloudron).
## Installing
[Install script](https://cloudron.io/documentation/installation/) - [Pricing](https://cloudron.io/pricing.html)
You can install the Cloudron platform on your own server or get a managed server
from cloudron.io. In either case, the Cloudron platform will keep your server and
apps up-to-date and secure.
**Note:** This repo is a small part of what gets installed on your server - there is
the dashboard, database addons, graph container, base image etc. Cloudron also relies
on external services such as the App Store for apps to be installed. As such, don't
clone this repo and npm install and expect something to work.
* [Selfhosting](https://cloudron.io/documentation/installation/) - [Pricing](https://cloudron.io/pricing.html)
* [Managed Hosting](https://cloudron.io/managed.html)
## Support
## Documentation
* [Documentation](https://cloudron.io/documentation/)
* [Forum](https://forum.cloudron.io/)
## Related repos
The [base image repo](https://git.cloudron.io/cloudron/docker-base-image) is the parent image of all
the containers in the Cloudron.
## Community
* [Forum](https://forum.cloudron.io/)
* [Support](mailto:support@cloudron.io)
-1
View File
@@ -1 +0,0 @@
# release version. do not edit manually
-193
View File
@@ -1,193 +0,0 @@
#!/bin/bash
set -eu -o pipefail
assertNotEmpty() {
: "${!1:? "$1 is not set."}"
}
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"/.. && pwd)"
export JSON="${SOURCE_DIR}/node_modules/.bin/json"
INSTANCE_TYPE="t2.micro"
BLOCK_DEVICE="DeviceName=/dev/sda1,Ebs={VolumeSize=20,DeleteOnTermination=true,VolumeType=gp2}"
SSH_KEY_NAME="id_rsa_yellowtent"
revision=$(git rev-parse HEAD)
ami_name=""
server_id=""
server_ip=""
destroy_server="yes"
deploy_env="prod"
image_id=""
args=$(getopt -o "" -l "revision:,name:,no-destroy,env:,region:" -n "$0" -- "$@")
eval set -- "${args}"
while true; do
case "$1" in
--env) deploy_env="$2"; shift 2;;
--revision) revision="$2"; shift 2;;
--name) ami_name="$2"; shift 2;;
--no-destroy) destroy_server="no"; shift 2;;
--region)
case "$2" in
"us-east-1")
image_id="ami-6edd3078"
security_group="sg-a5e17fd9"
subnet_id="subnet-b8fbc0f1"
;;
"eu-central-1")
image_id="ami-5aee2235"
security_group="sg-19f5a770" # everything open on eu-central-1
subnet_id=""
;;
*)
echo "Unknown aws region $2"
exit 1
;;
esac
export AWS_DEFAULT_REGION="$2" # used by the aws cli tool
shift 2
;;
--) break;;
*) echo "Unknown option $1"; exit 1;;
esac
done
# TODO fix this
export AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY}"
export AWS_SECRET_ACCESS_KEY="${AWS_ACCESS_SECRET}"
readonly ssh_keys="${HOME}/.ssh/id_rsa_yellowtent"
readonly SSH="ssh -o IdentitiesOnly=yes -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i ${ssh_keys}"
if [[ ! -f "${ssh_keys}" ]]; then
echo "caas ssh key is missing at ${ssh_keys} (pick it up from secrets repo)"
exit 1
fi
if [[ -z "${image_id}" ]]; then
echo "--region is required (us-east-1 or eu-central-1)"
exit 1
fi
function get_pretty_revision() {
local git_rev="$1"
local sha1=$(git rev-parse --short "${git_rev}" 2>/dev/null)
echo "${sha1}"
}
function wait_for_ssh() {
echo "=> Waiting for ssh connection"
while true; do
echo -n "."
if $SSH ubuntu@${server_ip} echo "hello"; then
echo ""
break
fi
sleep 5
done
}
now=$(date "+%Y-%m-%d-%H%M%S")
pretty_revision=$(get_pretty_revision "${revision}")
if [[ -z "${ami_name}" ]]; then
ami_name="box-${deploy_env}-${pretty_revision}-${now}"
fi
echo "=> Create EC2 instance"
id=$(aws ec2 run-instances --image-id "${image_id}" --instance-type "${INSTANCE_TYPE}" --security-group-ids "${security_group}" --block-device-mappings "${BLOCK_DEVICE}" --key-name "${SSH_KEY_NAME}" --subnet-id "${subnet_id}" --associate-public-ip-address \
| $JSON Instances \
| $JSON 0.InstanceId)
[[ -z "$id" ]] && exit 1
echo "Instance created ID $id"
echo "=> Waiting for instance to get a public IP"
while true; do
server_ip=$(aws ec2 describe-instances --instance-ids ${id} \
| $JSON Reservations.0.Instances \
| $JSON 0.PublicIpAddress)
if [[ ! -z "${server_ip}" ]]; then
echo ""
break
fi
echo -n "."
sleep 1
done
echo "Got public IP ${server_ip}"
wait_for_ssh
echo "=> Fetching cloudron-setup"
while true; do
if $SSH ubuntu@${server_ip} wget "https://cloudron.io/cloudron-setup" -O "cloudron-setup"; then
echo ""
break
fi
echo -n "."
sleep 5
done
echo "=> Running cloudron-setup"
$SSH ubuntu@${server_ip} sudo /bin/bash "cloudron-setup" --env "${deploy_env}" --provider "ami" --skip-reboot
wait_for_ssh
echo "=> Removing ssh key"
$SSH ubuntu@${server_ip} sudo rm /home/ubuntu/.ssh/authorized_keys /root/.ssh/authorized_keys
echo "=> Creating AMI"
image_id=$(aws ec2 create-image --instance-id "${id}" --name "${ami_name}" | $JSON ImageId)
[[ -z "$id" ]] && exit 1
echo "Creating AMI with Id ${image_id}"
echo "=> Waiting for AMI to be created"
while true; do
state=$(aws ec2 describe-images --image-ids ${image_id} \
| $JSON Images \
| $JSON 0.State)
if [[ "${state}" == "available" ]]; then
echo ""
break
fi
echo -n "."
sleep 5
done
if [[ "${destroy_server}" == "yes" ]]; then
echo "=> Deleting EC2 instance"
while true; do
state=$(aws ec2 terminate-instances --instance-id "${id}" \
| $JSON TerminatingInstances \
| $JSON 0.CurrentState.Name)
if [[ "${state}" == "shutting-down" ]]; then
echo ""
break
fi
echo -n "."
sleep 5
done
fi
echo ""
echo "Done."
echo ""
echo "New AMI is: ${image_id}"
echo ""
-261
View File
@@ -1,261 +0,0 @@
#!/bin/bash
if [[ -z "${DIGITAL_OCEAN_TOKEN}" ]]; then
echo "Script requires DIGITAL_OCEAN_TOKEN env to be set"
exit 1
fi
if [[ -z "${JSON}" ]]; then
echo "Script requires JSON env to be set to path of JSON binary"
exit 1
fi
readonly CURL="curl --retry 5 -s -u ${DIGITAL_OCEAN_TOKEN}:"
function debug() {
echo "$@" >&2
}
function get_ssh_key_id() {
id=$($CURL "https://api.digitalocean.com/v2/account/keys" \
| $JSON ssh_keys \
| $JSON -c "this.name === \"$1\"" \
| $JSON 0.id)
[[ -z "$id" ]] && exit 1
echo "$id"
}
function create_droplet() {
local ssh_key_id="$1"
local box_name="$2"
local image_region="sfo2"
local ubuntu_image_slug="ubuntu-16-04-x64"
local box_size="1gb"
local data="{\"name\":\"${box_name}\",\"size\":\"${box_size}\",\"region\":\"${image_region}\",\"image\":\"${ubuntu_image_slug}\",\"ssh_keys\":[ \"${ssh_key_id}\" ],\"backups\":false}"
id=$($CURL -X POST -H 'Content-Type: application/json' -d "${data}" "https://api.digitalocean.com/v2/droplets" | $JSON droplet.id)
[[ -z "$id" ]] && exit 1
echo "$id"
}
function get_droplet_ip() {
local droplet_id="$1"
ip=$($CURL "https://api.digitalocean.com/v2/droplets/${droplet_id}" | $JSON "droplet.networks.v4[0].ip_address")
[[ -z "$ip" ]] && exit 1
echo "$ip"
}
function get_droplet_id() {
local droplet_name="$1"
id=$($CURL "https://api.digitalocean.com/v2/droplets?per_page=200" | $JSON "droplets" | $JSON -c "this.name === '${droplet_name}'" | $JSON "[0].id")
[[ -z "$id" ]] && exit 1
echo "$id"
}
function power_off_droplet() {
local droplet_id="$1"
local data='{"type":"power_off"}'
local response=$($CURL -X POST -H 'Content-Type: application/json' -d "${data}" "https://api.digitalocean.com/v2/droplets/${droplet_id}/actions")
local event_id=`echo "${response}" | $JSON action.id`
if [[ -z "${event_id}" ]]; then
debug "Got no event id, assuming already powered off."
debug "Response: ${response}"
return
fi
debug "Powered off droplet. Event id: ${event_id}"
debug -n "Waiting for droplet to power off"
while true; do
local event_status=`$CURL "https://api.digitalocean.com/v2/droplets/${droplet_id}/actions/${event_id}" | $JSON action.status`
if [[ "${event_status}" == "completed" ]]; then
break
fi
debug -n "."
sleep 10
done
debug ""
}
function power_on_droplet() {
local droplet_id="$1"
local data='{"type":"power_on"}'
local event_id=`$CURL -X POST -H 'Content-Type: application/json' -d "${data}" "https://api.digitalocean.com/v2/droplets/${droplet_id}/actions" | $JSON action.id`
debug "Powered on droplet. Event id: ${event_id}"
if [[ -z "${event_id}" ]]; then
debug "Got no event id, assuming already powered on"
return
fi
debug -n "Waiting for droplet to power on"
while true; do
local event_status=`$CURL "https://api.digitalocean.com/v2/droplets/${droplet_id}/actions/${event_id}" | $JSON action.status`
if [[ "${event_status}" == "completed" ]]; then
break
fi
debug -n "."
sleep 10
done
debug ""
}
function get_image_id() {
local snapshot_name="$1"
local image_id=""
if ! response=$($CURL "https://api.digitalocean.com/v2/images?per_page=200"); then
echo "Failed to get image listing. ${response}"
return 1
fi
if ! image_id=$(echo "$response" \
| $JSON images \
| $JSON -c "this.name === \"${snapshot_name}\"" 0.id); then
echo "Failed to parse curl response: ${response}"
return 1
fi
if [[ -z "${image_id}" ]]; then
echo "Failed to get image id of ${snapshot_name}. reponse: ${response}"
return 1
fi
echo "${image_id}"
}
function snapshot_droplet() {
local droplet_id="$1"
local snapshot_name="$2"
local data="{\"type\":\"snapshot\",\"name\":\"${snapshot_name}\"}"
local event_id=`$CURL -X POST -H 'Content-Type: application/json' -d "${data}" "https://api.digitalocean.com/v2/droplets/${droplet_id}/actions" | $JSON action.id`
debug "Droplet snapshotted as ${snapshot_name}. Event id: ${event_id}"
debug -n "Waiting for snapshot to complete"
while true; do
if ! response=$($CURL "https://api.digitalocean.com/v2/droplets/${droplet_id}/actions/${event_id}"); then
echo "Could not get action status. ${response}"
continue
fi
if ! event_status=$(echo "${response}" | $JSON action.status); then
echo "Could not parse action.status from response. ${response}"
continue
fi
if [[ "${event_status}" == "completed" ]]; then
break
fi
debug -n "."
sleep 10
done
debug "! done"
if ! image_id=$(get_image_id "${snapshot_name}"); then
return 1
fi
echo "${image_id}"
}
function destroy_droplet() {
local droplet_id="$1"
# TODO: check for 204 status
$CURL -X DELETE "https://api.digitalocean.com/v2/droplets/${droplet_id}"
debug "Droplet destroyed"
debug ""
}
function transfer_image() {
local image_id="$1"
local region_slug="$2"
local data="{\"type\":\"transfer\",\"region\":\"${region_slug}\"}"
local event_id=`$CURL -X POST -H 'Content-Type: application/json' -d "${data}" "https://api.digitalocean.com/v2/images/${image_id}/actions" | $JSON action.id`
echo "${event_id}"
}
function wait_for_image_event() {
local image_id="$1"
local event_id="$2"
debug -n "Waiting for ${event_id}"
while true; do
local event_status=`$CURL "https://api.digitalocean.com/v2/images/${image_id}/actions/${event_id}" | $JSON action.status`
if [[ "${event_status}" == "completed" ]]; then
break
fi
debug -n "."
sleep 10
done
debug ""
}
function transfer_image_to_all_regions() {
local image_id="$1"
xfer_events=()
image_regions=(ams2) ## sfo1 is where the image is created
for image_region in ${image_regions[@]}; do
xfer_event=$(transfer_image ${image_id} ${image_region})
echo "Image transfer to ${image_region} initiated. Event id: ${xfer_event}"
xfer_events+=("${xfer_event}")
sleep 1
done
echo "Image transfer initiated, but they will take some time to get transferred."
for xfer_event in ${xfer_events[@]}; do
$vps wait_for_image_event "${image_id}" "${xfer_event}"
done
}
if [[ $# -lt 1 ]]; then
debug "<command> <params...>"
exit 1
fi
case $1 in
get_ssh_key_id)
get_ssh_key_id "${@:2}"
;;
create)
create_droplet "${@:2}"
;;
get_id)
get_droplet_id "${@:2}"
;;
get_ip)
get_droplet_ip "${@:2}"
;;
power_on)
power_on_droplet "${@:2}"
;;
power_off)
power_off_droplet "${@:2}"
;;
snapshot)
snapshot_droplet "${@:2}"
;;
destroy)
destroy_droplet "${@:2}"
;;
transfer_image_to_all_regions)
transfer_image_to_all_regions "${@:2}"
;;
*)
echo "Unknown command $1"
exit 1
esac
-164
View File
@@ -1,164 +0,0 @@
#!/bin/bash
set -euv -o pipefail
readonly SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly arg_provider="${1:-generic}"
readonly arg_infraversionpath="${SOURCE_DIR}/${2:-}"
function die {
echo $1
exit 1
}
export DEBIAN_FRONTEND=noninteractive
# hold grub since updating it breaks on some VPS providers. also, dist-upgrade will trigger it
apt-mark hold grub* >/dev/null
apt-get -o Dpkg::Options::="--force-confdef" update -y
apt-get -o Dpkg::Options::="--force-confdef" upgrade -y
apt-mark unhold grub* >/dev/null
echo "==> Installing required packages"
debconf-set-selections <<< 'mysql-server mysql-server/root_password password password'
debconf-set-selections <<< 'mysql-server mysql-server/root_password_again password password'
# this enables automatic security upgrades (https://help.ubuntu.com/community/AutomaticSecurityUpdates)
# resolvconf is needed for unbound to work property after disabling systemd-resolved in 18.04
ubuntu_version=$(lsb_release -rs)
ubuntu_codename=$(lsb_release -cs)
gpg_package=$([[ "${ubuntu_version}" == "16.04" ]] && echo "gnupg" || echo "gpg")
apt-get -y install \
acl \
build-essential \
cifs-utils \
cron \
curl \
debconf-utils \
dmsetup \
$gpg_package \
iptables \
libpython2.7 \
linux-generic \
logrotate \
mysql-server-5.7 \
openssh-server \
pwgen \
resolvconf \
swaks \
tzdata \
unattended-upgrades \
unbound \
xfsprogs
if [[ "${ubuntu_version}" == "16.04" ]]; then
echo "==> installing nginx for xenial for TLSv3 support"
curl -sL http://nginx.org/packages/ubuntu/pool/nginx/n/nginx/nginx_1.14.0-1~xenial_amd64.deb -o /tmp/nginx.deb
# apt install with install deps (as opposed to dpkg -i)
apt install -y /tmp/nginx.deb
rm /tmp/nginx.deb
else
apt install -y nginx-full
fi
# on some providers like scaleway the sudo file is changed and we want to keep the old one
apt-get -o Dpkg::Options::="--force-confold" install -y sudo
# this ensures that unattended upgades are enabled, if it was disabled during ubuntu install time (see #346)
# debconf-set-selection of unattended-upgrades/enable_auto_updates + dpkg-reconfigure does not work
cp /usr/share/unattended-upgrades/20auto-upgrades /etc/apt/apt.conf.d/20auto-upgrades
echo "==> Installing node.js"
mkdir -p /usr/local/node-10.18.1
curl -sL https://nodejs.org/dist/v10.18.1/node-v10.18.1-linux-x64.tar.gz | tar zxvf - --strip-components=1 -C /usr/local/node-10.18.1
ln -sf /usr/local/node-10.18.1/bin/node /usr/bin/node
ln -sf /usr/local/node-10.18.1/bin/npm /usr/bin/npm
apt-get install -y python # Install python which is required for npm rebuild
[[ "$(python --version 2>&1)" == "Python 2.7."* ]] || die "Expecting python version to be 2.7.x"
# https://docs.docker.com/engine/installation/linux/ubuntulinux/
echo "==> Installing Docker"
# create systemd drop-in file. if you channge options here, be sure to fixup installer.sh as well
mkdir -p /etc/systemd/system/docker.service.d
echo -e "[Service]\nExecStart=\nExecStart=/usr/bin/dockerd -H fd:// --log-driver=journald --exec-opt native.cgroupdriver=cgroupfs --storage-driver=overlay2" > /etc/systemd/system/docker.service.d/cloudron.conf
# there are 3 packages for docker - containerd, CLI and the daemon
curl -sL "https://download.docker.com/linux/ubuntu/dists/${ubuntu_codename}/pool/stable/amd64/containerd.io_1.2.2-3_amd64.deb" -o /tmp/containerd.deb
curl -sL "https://download.docker.com/linux/ubuntu/dists/${ubuntu_codename}/pool/stable/amd64/docker-ce-cli_18.09.2~3-0~ubuntu-${ubuntu_codename}_amd64.deb" -o /tmp/docker-ce-cli.deb
curl -sL "https://download.docker.com/linux/ubuntu/dists/${ubuntu_codename}/pool/stable/amd64/docker-ce_18.09.2~3-0~ubuntu-${ubuntu_codename}_amd64.deb" -o /tmp/docker.deb
# apt install with install deps (as opposed to dpkg -i)
apt install -y /tmp/containerd.deb /tmp/docker-ce-cli.deb /tmp/docker.deb
rm /tmp/containerd.deb /tmp/docker-ce-cli.deb /tmp/docker.deb
storage_driver=$(docker info | grep "Storage Driver" | sed 's/.*: //')
if [[ "${storage_driver}" != "overlay2" ]]; then
echo "Docker is using "${storage_driver}" instead of overlay2"
exit 1
fi
# do not upgrade grub because it might prompt user and break this script
echo "==> Enable memory accounting"
apt-get -y --no-upgrade install grub2-common
sed -e 's/^GRUB_CMDLINE_LINUX="\(.*\)"$/GRUB_CMDLINE_LINUX="\1 cgroup_enable=memory swapaccount=1 panic_on_oops=1 panic=5"/' -i /etc/default/grub
update-grub
echo "==> Downloading docker images"
if [ ! -f "${arg_infraversionpath}/infra_version.js" ]; then
echo "No infra_versions.js found"
exit 1
fi
images=$(node -e "var i = require('${arg_infraversionpath}/infra_version.js'); console.log(i.baseImages.map(function (x) { return x.tag; }).join(' '), Object.keys(i.images).map(function (x) { return i.images[x].tag; }).join(' '));")
echo -e "\tPulling docker images: ${images}"
for image in ${images}; do
docker pull "${image}"
docker pull "${image%@sha256:*}" # this will tag the image for readability
done
echo "==> Install collectd"
if ! apt-get install -y libcurl3-gnutls collectd collectd-utils; then
# FQDNLookup is true in default debian config. The box code has a custom collectd.conf that fixes this
echo "Failed to install collectd. Presumably because of http://mailman.verplant.org/pipermail/collectd/2015-March/006491.html"
sed -e 's/^FQDNLookup true/FQDNLookup false/' -i /etc/collectd/collectd.conf
fi
echo "==> Configuring host"
sed -e 's/^#NTP=/NTP=0.ubuntu.pool.ntp.org 1.ubuntu.pool.ntp.org 2.ubuntu.pool.ntp.org 3.ubuntu.pool.ntp.org/' -i /etc/systemd/timesyncd.conf
timedatectl set-ntp 1
# mysql follows the system timezone
timedatectl set-timezone UTC
echo "==> Adding sshd configuration warning"
sed -e '/Port 22/ i # NOTE: Cloudron only supports moving SSH to port 202. See https://cloudron.io/documentation/security/#securing-ssh-access' -i /etc/ssh/sshd_config
# https://bugs.launchpad.net/ubuntu/+source/base-files/+bug/1701068
echo "==> Disabling motd news"
sed -i 's/^ENABLED=.*/ENABLED=0/' /etc/default/motd-news
# Disable bind for good measure (on online.net, kimsufi servers these are pre-installed and conflicts with unbound)
systemctl stop bind9 || true
systemctl disable bind9 || true
# on ovh images dnsmasq seems to run by default
systemctl stop dnsmasq || true
systemctl disable dnsmasq || true
# on ssdnodes postfix seems to run by default
systemctl stop postfix || true
systemctl disable postfix || true
# on ubuntu 18.04, this is the default. this requires resolvconf for DNS to work further after the disable
systemctl stop systemd-resolved || true
systemctl disable systemd-resolved || true
# ubuntu's default config for unbound does not work if ipv6 is disabled. this config is overwritten in start.sh
# we need unbound to work as this is required for installer.sh to do any DNS requests
ip6=$([[ -s /proc/net/if_inet6 ]] && echo "yes" || echo "no")
echo -e "server:\n\tinterface: 127.0.0.1\n\tdo-ip6: ${ip6}" > /etc/unbound/unbound.conf.d/cloudron-network.conf
systemctl restart unbound
-58
View File
@@ -1,58 +0,0 @@
#!/usr/bin/env node
'use strict';
// prefix all output with a timestamp
// debug() already prefixes and uses process.stderr NOT console.*
['log', 'info', 'warn', 'debug', 'error'].forEach(function (log) {
var orig = console[log];
console[log] = function () {
orig.apply(console, [new Date().toISOString()].concat(Array.prototype.slice.call(arguments)));
};
});
require('supererror')({ splatchError: true });
let async = require('async'),
constants = require('./src/constants.js'),
dockerProxy = require('./src/dockerproxy.js'),
ldap = require('./src/ldap.js'),
server = require('./src/server.js');
console.log();
console.log('==========================================');
console.log(` Cloudron ${constants.VERSION} `);
console.log('==========================================');
console.log();
async.series([
server.start,
ldap.start,
dockerProxy.start
], function (error) {
if (error) {
console.error('Error starting server', error);
process.exit(1);
}
console.log('Cloudron is up and running');
});
var NOOP_CALLBACK = function () { };
process.on('SIGINT', function () {
console.log('Received SIGINT. Shutting down.');
server.stop(NOOP_CALLBACK);
ldap.stop(NOOP_CALLBACK);
dockerProxy.stop(NOOP_CALLBACK);
setTimeout(process.exit.bind(process), 3000);
});
process.on('SIGTERM', function () {
console.log('Received SIGTERM. Shutting down.');
server.stop(NOOP_CALLBACK);
ldap.stop(NOOP_CALLBACK);
dockerProxy.stop(NOOP_CALLBACK);
setTimeout(process.exit.bind(process), 3000);
});
-28
View File
@@ -1,28 +0,0 @@
#!/usr/bin/env node
'use strict';
var database = require('./src/database.js');
var crashNotifier = require('./src/crashnotifier.js');
// This is triggered by systemd with the crashed unit name as argument
function main() {
if (process.argv.length !== 3) return console.error('Usage: crashnotifier.js <unitName>');
var unitName = process.argv[2];
console.log('Started crash notifier for', unitName);
// eventlog api needs the db
database.initialize(function (error) {
if (error) return console.error('Cannot connect to database. Unable to send crash log.', error);
crashNotifier.sendFailureLogs(unitName, function (error) {
if (error) console.error(error);
process.exit();
});
});
}
main();
+248
View File
@@ -0,0 +1,248 @@
/* jslint node:true */
'use strict';
var argv = require('yargs').argv,
autoprefixer = require('gulp-autoprefixer'),
concat = require('gulp-concat'),
cssnano = require('gulp-cssnano'),
ejs = require('gulp-ejs'),
gulp = require('gulp'),
rimraf = require('rimraf'),
sass = require('gulp-sass'),
serve = require('gulp-serve'),
sourcemaps = require('gulp-sourcemaps'),
uglify = require('gulp-uglify'),
url = require('url');
gulp.task('3rdparty', function () {
gulp.src([
'webadmin/src/3rdparty/**/*.js',
'webadmin/src/3rdparty/**/*.map',
'webadmin/src/3rdparty/**/*.css',
'webadmin/src/3rdparty/**/*.otf',
'webadmin/src/3rdparty/**/*.eot',
'webadmin/src/3rdparty/**/*.svg',
'webadmin/src/3rdparty/**/*.gif',
'webadmin/src/3rdparty/**/*.ttf',
'webadmin/src/3rdparty/**/*.woff',
'webadmin/src/3rdparty/**/*.woff2'
])
.pipe(gulp.dest('webadmin/dist/3rdparty/'));
gulp.src('node_modules/bootstrap-sass/assets/javascripts/bootstrap.min.js')
.pipe(gulp.dest('webadmin/dist/3rdparty/js'));
});
// --------------
// JavaScript
// --------------
if (argv.help || argv.h) {
console.log('Supported arguments for "gulp develop":');
console.log(' --client-id <clientId>');
console.log(' --client-secret <clientSecret>');
console.log(' --api-origin <cloudron api uri>');
process.exit(1);
}
gulp.task('js', ['js-index', 'js-logs', 'js-terminal', 'js-setup', 'js-setupdns', 'js-restore', 'js-update'], function () {});
var oauth = {
clientId: argv.clientId || 'cid-webadmin',
clientSecret: argv.clientSecret || 'unused',
apiOrigin: argv.apiOrigin || '',
apiOriginHostname: argv.apiOrigin ? url.parse(argv.apiOrigin).hostname : ''
};
console.log();
console.log('Using OAuth credentials:');
console.log(' ClientId: %s', oauth.clientId);
console.log(' ClientSecret: %s', oauth.clientSecret);
console.log(' Cloudron API: %s', oauth.apiOrigin || 'default');
console.log(' Cloudron Host: %s', oauth.apiOriginHostname);
console.log();
gulp.task('js-index', function () {
// needs special treatment for error handling
var uglifyer = uglify();
uglifyer.on('error', function (error) {
console.error(error);
});
gulp.src([
'webadmin/src/js/index.js',
'webadmin/src/js/client.js',
'webadmin/src/js/appstore.js',
'webadmin/src/js/main.js',
'webadmin/src/views/*.js'
])
.pipe(ejs({ oauth: oauth }, {}, { ext: '.js' }))
.pipe(sourcemaps.init())
.pipe(concat('index.js', { newLine: ';' }))
.pipe(uglifyer)
.pipe(sourcemaps.write())
.pipe(gulp.dest('webadmin/dist/js'));
});
gulp.task('js-logs', function () {
// needs special treatment for error handling
var uglifyer = uglify();
uglifyer.on('error', function (error) {
console.error(error);
});
gulp.src(['webadmin/src/js/logs.js', 'webadmin/src/js/client.js'])
.pipe(ejs({ oauth: oauth }, {}, { ext: '.js' }))
.pipe(sourcemaps.init())
.pipe(concat('logs.js', { newLine: ';' }))
.pipe(uglifyer)
.pipe(sourcemaps.write())
.pipe(gulp.dest('webadmin/dist/js'));
});
gulp.task('js-terminal', function () {
// needs special treatment for error handling
var uglifyer = uglify();
uglifyer.on('error', function (error) {
console.error(error);
});
gulp.src(['webadmin/src/js/terminal.js', 'webadmin/src/js/client.js'])
.pipe(ejs({ oauth: oauth }, {}, { ext: '.js' }))
.pipe(sourcemaps.init())
.pipe(concat('terminal.js', { newLine: ';' }))
.pipe(uglifyer)
.pipe(sourcemaps.write())
.pipe(gulp.dest('webadmin/dist/js'));
});
gulp.task('js-setup', function () {
// needs special treatment for error handling
var uglifyer = uglify();
uglifyer.on('error', function (error) {
console.error(error);
});
gulp.src(['webadmin/src/js/setup.js', 'webadmin/src/js/client.js'])
.pipe(ejs({ oauth: oauth }, {}, { ext: '.js' }))
.pipe(sourcemaps.init())
.pipe(concat('setup.js', { newLine: ';' }))
.pipe(uglifyer)
.pipe(sourcemaps.write())
.pipe(gulp.dest('webadmin/dist/js'));
});
gulp.task('js-setupdns', function () {
// needs special treatment for error handling
var uglifyer = uglify();
uglifyer.on('error', function (error) {
console.error(error);
});
gulp.src(['webadmin/src/js/setupdns.js', 'webadmin/src/js/client.js'])
.pipe(ejs({ oauth: oauth }, {}, { ext: '.js' }))
.pipe(sourcemaps.init())
.pipe(concat('setupdns.js', { newLine: ';' }))
.pipe(uglifyer)
.pipe(sourcemaps.write())
.pipe(gulp.dest('webadmin/dist/js'));
});
gulp.task('js-restore', function () {
// needs special treatment for error handling
var uglifyer = uglify();
uglifyer.on('error', function (error) {
console.error(error);
});
gulp.src(['webadmin/src/js/restore.js', 'webadmin/src/js/client.js'])
.pipe(ejs({ oauth: oauth }, {}, { ext: '.js' }))
.pipe(sourcemaps.init())
.pipe(concat('restore.js', { newLine: ';' }))
.pipe(uglifyer)
.pipe(sourcemaps.write())
.pipe(gulp.dest('webadmin/dist/js'));
});
gulp.task('js-update', function () {
// needs special treatment for error handling
var uglifyer = uglify();
uglifyer.on('error', function (error) {
console.error(error);
});
gulp.src(['webadmin/src/js/update.js'])
.pipe(sourcemaps.init())
.pipe(uglifyer)
.pipe(sourcemaps.write())
.pipe(gulp.dest('webadmin/dist/js'));
});
// --------------
// HTML
// --------------
gulp.task('html', ['html-views', 'html-templates'], function () {
return gulp.src('webadmin/src/*.html').pipe(ejs({ apiOriginHostname: oauth.apiOriginHostname }, {}, { ext: '.html' })).pipe(gulp.dest('webadmin/dist'));
});
gulp.task('html-views', function () {
return gulp.src('webadmin/src/views/**/*.html').pipe(gulp.dest('webadmin/dist/views'));
});
gulp.task('html-templates', function () {
return gulp.src('webadmin/src/templates/**/*.html').pipe(gulp.dest('webadmin/dist/templates'));
});
// --------------
// CSS
// --------------
gulp.task('css', function () {
return gulp.src('webadmin/src/*.scss')
.pipe(sourcemaps.init())
.pipe(sass({ includePaths: ['node_modules/bootstrap-sass/assets/stylesheets/'] }).on('error', sass.logError))
.pipe(autoprefixer())
.pipe(cssnano())
.pipe(sourcemaps.write())
.pipe(gulp.dest('webadmin/dist'));
});
gulp.task('images', function () {
return gulp.src('webadmin/src/img/**')
.pipe(gulp.dest('webadmin/dist/img'));
});
// --------------
// Utilities
// --------------
gulp.task('watch', ['default'], function () {
gulp.watch(['webadmin/src/*.scss'], ['css']);
gulp.watch(['webadmin/src/img/*'], ['images']);
gulp.watch(['webadmin/src/**/*.html'], ['html']);
gulp.watch(['webadmin/src/views/*.html'], ['html-views']);
gulp.watch(['webadmin/src/templates/*.html'], ['html-templates']);
gulp.watch(['webadmin/src/js/update.js'], ['js-update']);
gulp.watch(['webadmin/src/js/setup.js', 'webadmin/src/js/client.js'], ['js-setup']);
gulp.watch(['webadmin/src/js/setupdns.js', 'webadmin/src/js/client.js'], ['js-setupdns']);
gulp.watch(['webadmin/src/js/restore.js', 'webadmin/src/js/client.js'], ['js-restore']);
gulp.watch(['webadmin/src/js/logs.js', 'webadmin/src/js/client.js'], ['js-logs']);
gulp.watch(['webadmin/src/js/terminal.js', 'webadmin/src/js/client.js'], ['js-terminal']);
gulp.watch(['webadmin/src/js/index.js', 'webadmin/src/js/client.js', 'webadmin/src/js/appstore.js', 'webadmin/src/js/main.js', 'webadmin/src/views/*.js'], ['js-index']);
gulp.watch(['webadmin/src/3rdparty/**/*'], ['3rdparty']);
});
gulp.task('clean', function () {
rimraf.sync('webadmin/dist');
});
gulp.task('default', ['clean', 'html', 'js', '3rdparty', 'images', 'css'], function () {});
gulp.task('develop', ['watch'], serve({ root: 'webadmin/dist', port: 4000 }));
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

-14
View File
@@ -1,14 +0,0 @@
'use strict';
var url = require('url');
exports.up = function(db, callback) {
var dbName = url.parse(process.env.DATABASE_URL).path.substr(1); // remove slash
// by default, mysql collates case insensitively. 'utf8_general_cs' is not available
db.runSql('ALTER DATABASE ' + dbName + ' DEFAULT CHARACTER SET=utf8 DEFAULT COLLATE utf8_bin', callback);
};
exports.down = function(db, callback) {
callback();
};
-18
View File
@@ -1,18 +0,0 @@
'use strict';
var fs = require('fs'),
async = require('async'),
path = require('path');
exports.up = function(db, callback) {
var schema = fs.readFileSync(path.join(__dirname, 'initial-schema.sql')).toString('utf8');
var statements = schema.split(';');
async.eachSeries(statements, function (statement, callback) {
if (statement.trim().length === 0) return callback(null);
db.runSql(statement, callback);
}, callback);
};
exports.down = function(db, callback) {
db.runSql('DROP TABLE users, tokens, clients, apps, appPortBindings, authcodes, settings', callback);
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE users ADD COLUMN resetToken VARCHAR(128) DEFAULT ""', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE users DROP COLUMN resetToken', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,19 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('DELETE FROM tokens', [], function (error) {
if (error) console.error(error);
db.runSql('ALTER TABLE tokens MODIFY expires BIGINT', [], function (error) {
if (error) console.error(error);
callback(error);
});
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE tokens MODIFY expires VARCHAR(512)', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE authcodes ADD COLUMN expiresAt BIGINT NOT NULL', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE authcodes DROP COLUMN expiresAt', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE appPortBindings ADD COLUMN environmentVariable VARCHAR(128) NOT NULL', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE appPortBindings DROP COLUMN environmentVariable', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE appPortBindings DROP COLUMN containerPort', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE appPortBindings ADD COLUMN containerPort VARCHAR(5) NOT NULL', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,19 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('DELETE FROM tokens', [], function (error) {
if (error) console.error(error);
db.runSql('ALTER TABLE tokens CHANGE userId identifier VARCHAR(128) NOT NULL', [], function (error) {
if (error) console.error(error);
callback(error);
});
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE tokens CHANGE identifier userId VARCHAR(128) NOT NULL', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps DROP COLUMN version', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps ADD COLUMN version VARCHAR(32)', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps DROP COLUMN healthy, ADD COLUMN health VARCHAR(128)', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps DROP COLUMN health, ADD COLUMN healthy INTEGER', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps ADD COLUMN lastBackupId VARCHAR(128)', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps DROP COLUMN lastBackupId', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps ADD COLUMN createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps DROP COLUMN createdAt', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,10 +0,0 @@
'use strict';
exports.up = function(db, callback) {
// everyday at 1am
db.runSql('INSERT settings (name, value) VALUES("autoupdate_pattern", ?)', [ '00 00 1 * * *' ], callback);
};
exports.down = function(db, callback) {
db.runSql('DELETE * FROM settings WHERE name="autoupdate_pattern"', [ ], callback);
};
@@ -1,14 +0,0 @@
'use strict';
var safe = require('safetydance');
exports.up = function(db, callback) {
var tz = safe.fs.readFileSync('/etc/timezone', 'utf8');
tz = tz ? tz.trim() : 'America/Los_Angeles';
db.runSql('INSERT settings (name, value) VALUES("time_zone", ?)', [ tz ], callback);
};
exports.down = function(db, callback) {
db.runSql('DELETE * FROM settings WHERE name="time_zone"', [ ], callback);
};
@@ -1,24 +0,0 @@
'use strict';
var async = require('async');
exports.up = function(db, callback) {
// http://stackoverflow.com/questions/386294/what-is-the-maximum-length-of-a-valid-email-address
async.series([
db.runSql.bind(db, 'ALTER TABLE users MODIFY username VARCHAR(254)'),
db.runSql.bind(db, 'ALTER TABLE users ADD CONSTRAINT users_username UNIQUE (username)'),
db.runSql.bind(db, 'ALTER TABLE users MODIFY email VARCHAR(254)'),
db.runSql.bind(db, 'ALTER TABLE users ADD CONSTRAINT users_email UNIQUE (email)'),
], callback);
};
exports.down = function(db, callback) {
async.series([
db.runSql.bind(db, 'ALTER TABLE users DROP INDEX users_username'),
db.runSql.bind(db, 'ALTER TABLE users MODIFY username VARCHAR(512)'),
db.runSql.bind(db, 'ALTER TABLE users DROP INDEX users_email'),
db.runSql.bind(db, 'ALTER TABLE users MODIFY email VARCHAR(512)'),
], callback);
};
@@ -1,17 +0,0 @@
'use strict';
var async = require('async');
exports.up = function(db, callback) {
async.series([
db.runSql.bind(db, 'ALTER TABLE users MODIFY username VARCHAR(254) NOT NULL'),
db.runSql.bind(db, 'ALTER TABLE users MODIFY email VARCHAR(254) NOT NULL'),
], callback);
};
exports.down = function(db, callback) {
async.series([
db.runSql.bind(db, 'ALTER TABLE users MODIFY username VARCHAR(254)'),
db.runSql.bind(db, 'ALTER TABLE users MODIFY email VARCHAR(254)'),
], callback);
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps ADD COLUMN lastManifestJson VARCHAR(2048)', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps DROP COLUMN lastManifestJson', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps CHANGE lastManifestJson lastBackupConfigJson VARCHAR(2048)', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps CHANGE lastBackupConfigJson lastManifestJson VARCHAR(2048)', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps ADD COLUMN oldConfigJson VARCHAR(2048)', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps DROP COLUMN oldConfigJson', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,9 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('DELETE FROM settings', [ ], callback);
};
exports.down = function(db, callback) {
callback();
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps ADD COLUMN oauthProxy BOOLEAN DEFAULT 0', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps DROP COLUMN oauthProxy', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,17 +0,0 @@
'use strict';
var async = require('async');
exports.up = function(db, callback) {
async.series([
db.runSql.bind(db, 'DELETE FROM clients'),
db.runSql.bind(db, 'ALTER TABLE clients ADD COLUMN type VARCHAR(16) NOT NULL'),
], callback);
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE clients DROP COLUMN type', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps CHANGE accessRestriction accessRestrictionJson VARCHAR(2048)', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps CHANGE accessRestrictionJson accessRestriction VARCHAR(2048)', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps MODIFY manifestJson TEXT', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps MODIFY manifestJson VARCHAR(2048)', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,19 +0,0 @@
'use strict';
var async = require('async');
exports.up = function(db, callback) {
async.series([
db.runSql.bind(db, 'ALTER TABLE apps MODIFY accessRestrictionJson TEXT'),
db.runSql.bind(db, 'ALTER TABLE apps MODIFY lastBackupConfigJson TEXT'),
db.runSql.bind(db, 'ALTER TABLE apps MODIFY oldConfigJson TEXT')
], callback);
};
exports.down = function(db, callback) {
async.series([
db.runSql.bind(db, 'ALTER TABLE apps MODIFY accessRestrictionJson VARCHAR(2048)'),
db.runSql.bind(db, 'ALTER TABLE apps MODIFY lastBackupConfigJson VARCHAR(2048)'),
db.runSql.bind(db, 'ALTER TABLE apps MODIFY oldConfigJson VARCHAR(2048)')
], callback);
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE users ADD COLUMN displayName VARCHAR(512) DEFAULT ""', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE users DROP COLUMN displayName', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps ADD COLUMN memoryLimit BIGINT DEFAULT 0', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps DROP COLUMN memoryLimit', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,20 +0,0 @@
'use strict';
exports.up = function(db, callback) {
var cmd = "CREATE TABLE userGroups(" +
"id VARCHAR(128) NOT NULL UNIQUE," +
"name VARCHAR(128) NOT NULL UNIQUE," +
"PRIMARY KEY(id))";
db.runSql(cmd, function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('DROP TABLE userGroups', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,21 +0,0 @@
'use strict';
exports.up = function(db, callback) {
var cmd = "CREATE TABLE IF NOT EXISTS groupMembers(" +
"groupId VARCHAR(128) NOT NULL," +
"userId VARCHAR(128) NOT NULL," +
"FOREIGN KEY(groupId) REFERENCES userGroups(id)," +
"FOREIGN KEY(userId) REFERENCES users(id));";
db.runSql(cmd, function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('DROP TABLE groupMembers', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,29 +0,0 @@
'use strict';
var async = require('async');
var ADMIN_GROUP_ID = 'admin'; // see constants.js
exports.up = function(db, callback) {
async.series([
db.runSql.bind(db, 'START TRANSACTION;'),
db.runSql.bind(db, 'INSERT INTO userGroups (id, name) VALUES (?, ?)', [ ADMIN_GROUP_ID, 'admin' ]),
function migrateAdminFlag(done) {
db.all('SELECT * FROM users WHERE admin=1', function (error, results) {
if (error) return done(error);
console.dir(results);
async.eachSeries(results, function (r, next) {
db.runSql('INSERT INTO groupMembers (groupId, userId) VALUES (?, ?)', [ ADMIN_GROUP_ID, r.id ], next);
}, done);
});
},
db.runSql.bind(db, 'ALTER TABLE users DROP COLUMN admin'),
db.runSql.bind(db, 'COMMIT')
], callback);
};
exports.down = function(db, callback) {
callback();
};
@@ -1,24 +0,0 @@
'use strict';
exports.up = function(db, callback) {
var cmd = "CREATE TABLE backups(" +
"filename VARCHAR(128) NOT NULL," +
"creationTime TIMESTAMP," +
"version VARCHAR(128) NOT NULL," +
"type VARCHAR(16) NOT NULL," +
"dependsOn VARCHAR(4096)," +
"state VARCHAR(16) NOT NULL," +
"PRIMARY KEY (filename))";
db.runSql(cmd, function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('DROP TABLE backups', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE backups ADD COLUMN configJson TEXT', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE backups DROP COLUMN configJson', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE backups DROP COLUMN configJson', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE backups ADD COLUMN configJson TEXT', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE backups CHANGE filename id VARCHAR(128)', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE backups CHANGE id filename VARCHAR(128)', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE users MODIFY username VARCHAR(254) UNIQUE', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE users MODIFY username VARCHAR(254) NOT NULL UNIQUE', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps ADD COLUMN altDomain VARCHAR(256)', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps DROP COLUMN altDomain', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,23 +0,0 @@
'use strict';
exports.up = function(db, callback) {
var cmd = "CREATE TABLE eventlog(" +
"id VARCHAR(128) NOT NULL," +
"source TEXT," +
"creationTime TIMESTAMP," +
"action VARCHAR(128) NOT NULL," +
"data TEXT," +
"PRIMARY KEY (id))";
db.runSql(cmd, function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('DROP TABLE eventlog', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE users ADD COLUMN showTutorial BOOLEAN DEFAULT 0', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE users DROP COLUMN showTutorial', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,21 +0,0 @@
'use strict';
exports.up = function(db, callback) {
var cmd = 'CREATE TABLE mailboxes(' +
'name VARCHAR(128) NOT NULL,' +
'aliasTarget VARCHAR(128),' +
'creationTime TIMESTAMP,' +
'PRIMARY KEY (name))';
db.runSql(cmd, function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('DROP TABLE mailboxes', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,26 +0,0 @@
'use strict';
var async = require('async');
// imports mailbox entries for existing users
exports.up = function(db, callback) {
async.series([
db.runSql.bind(db, 'START TRANSACTION;'),
function addUserMailboxes(done) {
db.all('SELECT username FROM users', function (error, results) {
if (error) return done(error);
async.eachSeries(results, function (r, next) {
if (!r.username) return next();
db.runSql('INSERT INTO mailboxes (name) VALUES (?)', [ r.username ], next);
}, done);
});
},
db.runSql.bind(db, 'COMMIT')
], callback);
};
exports.down = function(db, callback) {
callback();
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps DROP COLUMN lastBackupConfigJson', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps ADD COLUMN lastBackupConfigJson TEXT', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps MODIFY installationProgress TEXT', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps MODIFY installationProgress VARCHAR(512)', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps ADD COLUMN xFrameOptions VARCHAR(512)', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps DROP COLUMN xFrameOptions', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.all('SELECT id FROM users', function (error, results) {
if (error) return callback(error);
// existing cloudrons have email enabled by default. future cloudrons will have it disabled by default
var enable = results.length !== 0;
db.runSql('INSERT settings (name, value) VALUES("mail_config", ?)', [ JSON.stringify({ enabled: enable }) ], callback);
});
};
exports.down = function(db, callback) {
db.runSql('DELETE * FROM settings WHERE name="mail_config"', [ ], callback);
};
@@ -1,73 +0,0 @@
'use strict';
var async = require('async');
exports.up = function(db, callback) {
async.series([
db.runSql.bind(db, 'ALTER TABLE mailboxes ADD COLUMN ownerId VARCHAR(128)'),
db.runSql.bind(db, 'ALTER TABLE mailboxes ADD COLUMN ownerType VARCHAR(16)'),
db.runSql.bind(db, 'START TRANSACTION;'),
function addGroupMailboxes(done) {
console.log('Importing group mailboxes');
db.all('SELECT id, name FROM userGroups', function (error, results) {
if (error) return done(error);
async.eachSeries(results, function (g, next) {
db.runSql('INSERT INTO mailboxes (ownerId, ownerType, name) VALUES (?, ?, ?)', [ g.id, 'group', g.name ], function (error) {
if (error) console.error('Error importing group ' + JSON.stringify(g) + error);
next();
});
}, done);
});
},
function addAppMailboxes(done) {
console.log('Importing app mail boxes');
db.all('SELECT id, location, manifestJson FROM apps', function (error, results) {
if (error) return done(error);
async.eachSeries(results, function (a, next) {
var manifest = JSON.parse(a.manifestJson);
if (!manifest.addons['sendmail'] && !manifest.addons['recvmail']) return next();
var mailboxName = (a.location ? a.location : manifest.title.replace(/[^a-zA-Z0-9]/g, '')) + '.app';
db.runSql('INSERT INTO mailboxes (ownerId, ownerType, name) VALUES (?, ?, ?)', [ a.id, 'app', mailboxName ], function (error) {
if (error) console.error('Error importing app ' + JSON.stringify(a) + error);
next();
});
}, done);
});
},
function setUserMailboxOwnerIds(done) {
console.log('Setting owner id of user mailboxes and aliases');
db.all('SELECT id, username FROM users', function (error, results) {
if (error) return done(error);
async.eachSeries(results, function (u, next) {
if (!u.username) return next();
db.runSql('UPDATE mailboxes SET ownerId = ?, ownerType = ? WHERE name = ? OR aliasTarget = ?', [ u.id, 'user', u.username, u.username ], function (error) {
if (error) console.error('Error setting ownerid ' + JSON.stringify(u) + error);
next();
});
}, done);
});
},
db.runSql.bind(db, 'COMMIT'),
db.runSql.bind(db, 'ALTER TABLE mailboxes MODIFY ownerId VARCHAR(128) NOT NULL'),
db.runSql.bind(db, 'ALTER TABLE mailboxes MODIFY ownerType VARCHAR(128) NOT NULL'),
], callback);
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE mailboxes DROP COLUMN ownerId', function (error) {
if (error) console.error(error);
db.runSql('ALTER TABLE mailboxes DROP COLUMN ownerType', function (error) {
if (error) console.error(error);
callback(error);
});
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps ADD COLUMN sso BOOLEAN DEFAULT 1', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps DROP COLUMN sso', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps DROP COLUMN oauthProxy', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps ADD COLUMN oauthProxy BOOLEAN DEFAULT 0', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE users DROP COLUMN showTutorial', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE users ADD COLUMN showTutorial BOOLEAN DEFAULT 0', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps ADD COLUMN debugModeJson TEXT', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps DROP COLUMN debugModeJson ', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE backups MODIFY dependsOn TEXT', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE backups MODIFY dependsOn VARCHAR(4096)', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,16 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE appAddonConfigs ADD COLUMN name VARCHAR(128)', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE appAddonConfigs DROP COLUMN name', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,14 +0,0 @@
'use strict';
var url = require('url');
exports.up = function(db, callback) {
var dbName = url.parse(process.env.DATABASE_URL).path.substr(1); // remove slash
// by default, mysql collates case insensitively. 'utf8_general_cs' is not available
db.runSql('ALTER DATABASE ' + dbName + ' DEFAULT CHARACTER SET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci', callback);
};
exports.down = function(db, callback) {
callback();
};
@@ -1,95 +0,0 @@
'use strict';
var async = require('async');
// from apps.js DO NOT UPDATE WHEN apps.js changes, as this is part of db migration!!
function postProcess(result) {
try {
result.manifest = JSON.parse(result.manifestJson);
delete result.manifestJson;
result.oldConfig = JSON.parse(result.oldConfigJson);
delete result.oldConfigJson;
result.portBindings = { };
var hostPorts = result.hostPorts === null ? [ ] : result.hostPorts.split(',');
var environmentVariables = result.environmentVariables === null ? [ ] : result.environmentVariables.split(',');
delete result.hostPorts;
delete result.environmentVariables;
for (var i = 0; i < environmentVariables.length; i++) {
result.portBindings[environmentVariables[i]] = parseInt(hostPorts[i], 10);
}
result.accessRestriction = JSON.parse(result.accessRestrictionJson);
if (result.accessRestriction && !result.accessRestriction.users) result.accessRestriction.users = [];
delete result.accessRestrictionJson;
// TODO remove later once all apps have this attribute
result.xFrameOptions = result.xFrameOptions || 'SAMEORIGIN';
result.sso = !!result.sso; // make it bool
result.debugMode = JSON.parse(result.debugModeJson);
delete result.debugModeJson;
} catch (e) {
console.error('Failed to get restoreConfig for app.', e);
console.error('Falling back to empty values to make the update succeed.');
result.manifest = null;
}
}
// from apps.js DO NOT UPDATE WHEN apps.js changes, as this is part of db migration!!
var APPS_FIELDS_PREFIXED = [ 'apps.id', 'apps.appStoreId', 'apps.installationState', 'apps.installationProgress', 'apps.runState',
'apps.health', 'apps.containerId', 'apps.manifestJson', 'apps.httpPort', 'apps.location', 'apps.dnsRecordId',
'apps.accessRestrictionJson', 'apps.lastBackupId', 'apps.oldConfigJson', 'apps.memoryLimit', 'apps.altDomain',
'apps.xFrameOptions', 'apps.sso', 'apps.debugModeJson' ].join(',');
exports.up = function(db, callback) {
async.series([
db.runSql.bind(db, 'ALTER TABLE backups ADD COLUMN restoreConfigJson TEXT'),
// fill all the backups with restoreConfigs from current apps
function addRestoreConfigs(callback) {
console.log('Importing restoreConfigs');
var appQuery = 'SELECT ' + APPS_FIELDS_PREFIXED + ',' +
'GROUP_CONCAT(CAST(appPortBindings.hostPort AS CHAR(6))) AS hostPorts, GROUP_CONCAT(appPortBindings.environmentVariable) AS environmentVariables' +
' FROM apps LEFT OUTER JOIN appPortBindings ON apps.id = appPortBindings.appId' +
' GROUP BY apps.id ORDER BY apps.id';
db.all(appQuery, function (error, apps) {
if (error) return callback(error);
apps.forEach(postProcess);
async.eachSeries(apps, function (app, next) {
if (app.manifest === null) return next();
db.all('SELECT * FROM backups WHERE type="app" AND id LIKE "%app%\\_' + app.id + '\\_%"', function (error, backups) {
if (error) return next(error);
// from apps.js:getAppConfig()
var restoreConfig = {
manifest: app.manifest,
location: app.location,
accessRestriction: app.accessRestriction,
portBindings: app.portBindings,
memoryLimit: app.memoryLimit,
xFrameOptions: app.xFrameOptions || 'SAMEORIGIN',
altDomain: app.altDomain
};
async.eachSeries(backups, function (backup, next) {
db.runSql('UPDATE backups SET restoreConfigJson=?,creationTime=creationTime WHERE id=?', [ JSON.stringify(restoreConfig), backup.id ], next);
}, next);
});
}, callback);
});
}
], callback);
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE backups DROP COLUMN restoreConfigJson', callback);
};
@@ -1,22 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.all('SELECT value FROM settings WHERE name="backup_config"', function (error, results) {
if (error || results.length === 0) return callback(error);
var backupConfig = JSON.parse(results[0].value);
if (backupConfig.provider === 'filesystem') {
backupConfig.retentionSecs = 2 * 24 * 60 * 60; // 2 days
} else if (backupConfig.provider === 's3') { // S3
backupConfig.retentionSecs = -1;
} else if (backupConfig.provider === 'caas') {
backupConfig.retentionSecs = 10 * 24 * 60 * 60; // 10 days
}
db.runSql('UPDATE settings SET value=? WHERE name="backup_config"', [ JSON.stringify(backupConfig) ], callback);
});
};
exports.down = function(db, callback) {
callback();
};
@@ -1,9 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('INSERT settings (name, value) VALUES("mail_relay", ?)', [ JSON.stringify({ provider: 'cloudron-smtp' }) ], callback);
};
exports.down = function(db, callback) {
db.runSql('DELETE * FROM settings WHERE name="mail_relay"', [ ], callback);
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps ADD COLUMN robotsTxt TEXT', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps DROP COLUMN robotsTxt', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,29 +0,0 @@
'use strict';
// we used to have JSON as the db type for those two, however mariadb does not support it
// and we never used any JSON related features, but have the TEXT pattern everywhere
// This ensures all old cloudrons will have the columns altered
exports.up = function(db, callback) {
db.runSql('ALTER TABLE eventlog MODIFY data TEXT', [], function (error) {
if (error) console.error(error);
db.runSql('ALTER TABLE eventlog MODIFY source TEXT', [], function (error) {
if (error) console.error(error);
callback(error);
});
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE eventlog MODIFY data TEXT', [], function (error) {
if (error) console.error(error);
db.runSql('ALTER TABLE eventlog MODIFY source TEXT', [], function (error) {
if (error) console.error(error);
callback(error);
});
});
};
@@ -1,16 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps ADD COLUMN enableBackup BOOLEAN DEFAULT 1', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps DROP COLUMN enableBackup', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE settings MODIFY value TEXT', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE settings MODIFY value VARCHAR(512)', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,25 +0,0 @@
'use strict';
// ensure backupFolder and format are not empty
exports.up = function(db, callback) {
db.all('SELECT * FROM settings WHERE name=?', [ 'backup_config' ], function (error, result) {
if (error || result.length === 0) return callback(error);
var value = JSON.parse(result[0].value);
value.format = 'tgz'; // set the format
if (value.provider === 'filesystem' && !value.backupFolder) {
value.backupFolder = '/var/backups'; // set the backupFolder
}
db.runSql('UPDATE settings SET value = ? WHERE name = ?', [ JSON.stringify(value), 'backup_config' ], function (error) {
if (error) console.error('Error setting ownerid ' + JSON.stringify(u) + error);
callback();
});
});
};
exports.down = function(db, callback) {
callback();
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE backups ADD COLUMN format VARCHAR(16) DEFAULT "tgz"', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE backups DROP COLUMN format', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps ADD COLUMN newConfigJson TEXT', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps DROP COLUMN newConfigJson', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,40 +0,0 @@
'use strict';
var async = require('async');
exports.up = function(db, callback) {
async.series([
db.runSql.bind(db, 'ALTER TABLE backups ADD COLUMN manifestJson TEXT'),
db.runSql.bind(db, 'START TRANSACTION;'),
// fill all the backups with restoreConfigs from current apps
function addManifests(callback) {
console.log('Importing manifests');
db.all('SELECT * FROM backups WHERE type="app"', function (error, backups) {
if (error) return callback(error);
async.eachSeries(backups, function (backup, next) {
var m = backup.restoreConfigJson ? JSON.parse(backup.restoreConfigJson) : null;
if (m) m = JSON.stringify(m.manifest);
db.runSql('UPDATE backups SET manifestJson=? WHERE id=?', [ m, backup.id ], next);
}, callback);
});
},
db.runSql.bind(db, 'COMMIT'),
// remove the restoreConfig
db.runSql.bind(db, 'ALTER TABLE backups DROP COLUMN restoreConfigJson')
], callback);
};
exports.down = function(db, callback) {
async.series([
db.runSql.bind(db, 'ALTER TABLE backups DROP COLUMN manifestJson'),
db.runSql.bind(db, 'ALTER TABLE backups ADD COLUMN restoreConfigJson TEXT'),
], callback);
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps CHANGE newConfigJson updateConfigJson TEXT', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps CHANGE updateConfigJson newConfigJson TEXT', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps CHANGE lastBackupId restoreConfigJson TEXT', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps CHANGE restoreConfigJson lastBackupId TEXT', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,31 +0,0 @@
'use strict';
// WARNING!!
// At this point the default db collation is utf8mb4_unicode_ci however we already have foreign key constraits
// already with tables on utf8_bin charset, so we cannot convert all tables here to utf8mb4 collation without
// a reimport from a sql dump, as foreign keys across different collations are not supported
var async = require('async');
exports.up = function(db, callback) {
async.series([
db.runSql.bind(db, 'ALTER TABLE appPortBindings CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin'),
db.runSql.bind(db, 'ALTER TABLE apps CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin'),
db.runSql.bind(db, 'ALTER TABLE authcodes CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin'),
db.runSql.bind(db, 'ALTER TABLE backups CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin'),
db.runSql.bind(db, 'ALTER TABLE clients CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin'),
db.runSql.bind(db, 'ALTER TABLE eventlog CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin'),
db.runSql.bind(db, 'ALTER TABLE groupMembers CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin'),
db.runSql.bind(db, 'ALTER TABLE userGroups CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin'),
db.runSql.bind(db, 'ALTER TABLE mailboxes CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin'),
db.runSql.bind(db, 'ALTER TABLE migrations CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin'),
db.runSql.bind(db, 'ALTER TABLE settings CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin'),
db.runSql.bind(db, 'ALTER TABLE tokens CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin'),
db.runSql.bind(db, 'ALTER TABLE users CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin')
], callback);
};
exports.down = function(db, callback) {
// nothing to be done here
callback();
};
@@ -1,70 +0,0 @@
'use strict';
var async = require('async'),
safe = require('safetydance');
exports.up = function(db, callback) {
// first check precondtion of domain entry in settings
db.all('SELECT * FROM settings WHERE name = ?', [ 'domain' ], function (error, result) {
if (error) return callback(error);
var domain = {};
if (result[0]) domain = safe.JSON.parse(result[0].value) || {};
async.series([
db.runSql.bind(db, 'START TRANSACTION;'),
function addAppsDomainColumn(done) {
db.runSql('ALTER TABLE apps ADD COLUMN domain VARCHAR(128)', [], done);
},
function setAppDomain(done) {
if (!domain.fqdn) return done(); // skip for new cloudrons without a domain
db.runSql('UPDATE apps SET domain = ?', [ domain.fqdn ], done);
},
function addAppsLocationDomainUniqueConstraint(done) {
db.runSql('ALTER TABLE apps ADD UNIQUE location_domain_unique_index (location, domain)', [], done);
},
function removePresetupAdminGroupIfNew(done) {
// do not delete on update, will update the record in setMailboxesDomain()
if (domain.fqdn) return done();
// this will be finally created once we have a domain when we create the owner in user.js
const ADMIN_GROUP_ID = 'admin'; // see constants.js
db.runSql('DELETE FROM userGroups WHERE id = ?', [ ADMIN_GROUP_ID ], function (error) {
if (error) return done(error);
db.runSql('DELETE FROM mailboxes WHERE ownerId = ?', [ ADMIN_GROUP_ID ], done);
});
},
function addMailboxesDomainColumn(done) {
db.runSql('ALTER TABLE mailboxes ADD COLUMN domain VARCHAR(128)', [], done);
},
function setMailboxesDomain(done) {
if (!domain.fqdn) return done(); // skip for new cloudrons without a domain
db.runSql('UPDATE mailboxes SET domain = ?', [ domain.fqdn ], done);
},
function dropAppsLocationUniqueConstraint(done) {
db.runSql('ALTER TABLE apps DROP INDEX location', [], done);
},
db.runSql.bind(db, 'COMMIT')
], callback);
});
};
exports.down = function(db, callback) {
async.series([
db.runSql.bind(db, 'START TRANSACTION;'),
function dropMailboxesDomainColumn(done) {
db.runSql('ALTER TABLE mailboxes DROP COLUMN domain', [], done);
},
function dropLocationDomainUniqueConstraint(done) {
db.runSql('ALTER TABLE apps DROP INDEX location_domain_unique_index', [], done);
},
function dropAppsDomainColumn(done) {
db.runSql('ALTER TABLE apps DROP COLUMN domain', [], done);
},
function addAppsLocationUniqueConstraint(done) {
db.runSql('ALTER TABLE apps ADD UNIQUE location (location)', [], done);
},
db.runSql.bind(db, 'COMMIT')
], callback);
};
@@ -1,61 +0,0 @@
'use strict';
var async = require('async'),
safe = require('safetydance'),
tld = require('tldjs');
exports.up = function(db, callback) {
var fqdn, zoneName, configJson;
async.series([
function gatherDomain(done) {
db.all('SELECT * FROM settings WHERE name = ?', [ 'domain' ], function (error, result) {
if (error) return done(error);
var domain = {};
if (result[0]) domain = safe.JSON.parse(result[0].value) || {};
fqdn = domain.fqdn || ''; // will be null pre-setup
zoneName = domain.zoneName || tld.getDomain(fqdn) || fqdn;
done();
});
},
function gatherDNSConfig(done) {
db.all('SELECT * FROM settings WHERE name = ?', [ 'dns_config' ], function (error, result) {
if (error) return done(error);
configJson = (result[0] && result[0].value) ? result[0].value : JSON.stringify({ provider: 'manual'});
// caas dns config needs an fqdn
var config = JSON.parse(configJson);
if (config.provider === 'caas') config.fqdn = fqdn;
configJson = JSON.stringify(config);
done();
});
},
db.runSql.bind(db, 'START TRANSACTION;'),
function createDomainsTable(done) {
var cmd = `
CREATE TABLE domains(
domain VARCHAR(128) NOT NULL UNIQUE,
zoneName VARCHAR(128) NOT NULL,
configJson TEXT,
PRIMARY KEY (domain)) CHARACTER SET utf8 COLLATE utf8_bin
`;
db.runSql(cmd, [], done);
},
function addInitialDomain(done) {
if (!fqdn) return done();
db.runSql('INSERT INTO domains (domain, zoneName, configJson) VALUES (?, ?, ?)', [ fqdn, zoneName, configJson ], done);
},
db.runSql.bind(db, 'COMMIT')
], callback);
};
exports.down = function(db, callback) {
db.runSql('DROP TABLE domains', callback);
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps ADD CONSTRAINT apps_domain_constraint FOREIGN KEY(domain) REFERENCES domains(domain)', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps DROP FOREIGN KEY apps_domain_constraint', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE mailboxes ADD CONSTRAINT mailboxes_domain_constraint FOREIGN KEY(domain) REFERENCES domains(domain)', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE mailboxes DROP FOREIGN KEY mailboxes_domain_constraint', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE mailboxes DROP PRIMARY KEY', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE mailboxes ADD PRIMARY KEY(name)', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE mailboxes ADD UNIQUE mailboxes_name_domain_unique_index (name, domain)', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE mailboxes DROP INDEX mailboxes_name_domain_unique_index', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps ADD COLUMN updateTime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP', function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps DROP COLUMN updateTime', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,15 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.runSql('ALTER TABLE apps CHANGE createdAt creationTime TIMESTAMP(2) NOT NULL', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE apps CHANGE creationTime createdAt TIMESTAMP(2) NOT NULL', [], function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,28 +0,0 @@
'use strict';
var async = require('async');
// NOTE: This migration is incorrect because 'caas' domain is not guaranteed to be present in all Caas cloudrons
exports.up = function(db, callback) {
db.all('SELECT * FROM domains', function (error, domains) {
if (error) return callback(error);
var caasDomains = domains.filter(function (d) { return JSON.parse(d.configJson).provider === 'caas'; });
if (caasDomains.length === 0) return callback();
var caasDomain = caasDomains[0].domain;
db.all('SELECT * FROM settings WHERE name=?', [ 'backup_config' ], function (error, settings) {
if (error) return callback(error);
var setting = settings[0];
var config = JSON.parse(setting.value);
config.fqdn = caasDomain;
db.runSql('UPDATE settings SET value=? WHERE name=?', [ JSON.stringify(config), setting.name ], callback);
});
});
};
exports.down = function(db, callback) {
callback();
};
@@ -1,23 +0,0 @@
'use strict';
exports.up = function(db, callback) {
var backupConfig = {
"provider": "filesystem",
"backupFolder": "/var/backups",
"format": "tgz",
"retentionSecs": 172800
};
db.runSql('INSERT settings (name, value) VALUES(?, ?)', [ 'backup_config', JSON.stringify(backupConfig) ], function (error) {
if (!error || error.code === 'ER_DUP_ENTRY') return callback(); // dup entry is OK for existing cloudrons
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('DELETE FROM settings WHERE name=?', ['backup_config'], function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,33 +0,0 @@
'use strict';
var async = require('async');
exports.up = function(db, callback) {
// first check precondtion of domain entry in settings
db.all('SELECT * FROM domains', [ ], function (error, domains) {
if (error) return callback(error);
async.series([
db.runSql.bind(db, 'START TRANSACTION;'),
db.runSql.bind(db, 'ALTER TABLE domains ADD COLUMN provider VARCHAR(16) DEFAULT ""'),
function setProvider(done) {
async.eachSeries(domains, function (domain, iteratorCallback) {
var config = JSON.parse(domain.configJson);
var provider = config.provider;
delete config.provider;
db.runSql('UPDATE domains SET provider = ?, configJson = ? WHERE domain = ?', [ provider, JSON.stringify(config), domain.domain ], iteratorCallback);
}, done);
},
db.runSql.bind(db, 'ALTER TABLE domains MODIFY provider VARCHAR(16) NOT NULL'),
db.runSql.bind(db, 'COMMIT')
], callback);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE domains DROP COLUMN provider', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,24 +0,0 @@
'use strict';
exports.up = function(db, callback) {
var cmd = 'CREATE TABLE IF NOT EXISTS mail(' +
'domain VARCHAR(128) NOT NULL UNIQUE,' +
'enabled BOOLEAN DEFAULT 0,' +
'mailFromValidation BOOLEAN DEFAULT 1,' +
'catchAllJson TEXT,' +
'relayJson TEXT,' +
'FOREIGN KEY(domain) REFERENCES domains(domain),' +
'PRIMARY KEY(domain)) CHARACTER SET utf8 COLLATE utf8_bin';
db.runSql(cmd, function (error) {
if (error) console.error(error);
callback(error);
});
};
exports.down = function(db, callback) {
db.runSql('DROP TABLE mail', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,34 +0,0 @@
'use strict';
exports.up = function(db, callback) {
db.all('SELECT * FROM domains', function (error, domains) {
if (error) return callback(error);
if (domains.length === 0) return callback();
db.all('SELECT * FROM settings', function (error, allSettings) {
if (error) return callback(error);
// defaults
var mailFromValidation = true;
var catchAll = [ ];
var relay = { provider: 'cloudron-smtp' };
var mailEnabled = false;
allSettings.forEach(function (setting) {
switch (setting.name) {
case 'mail_from_validation': mailFromValidation = !!setting.value; break;
case 'catch_all_address': catchAll = JSON.parse(setting.value); break;
case 'mail_relay': relay = JSON.parse(setting.value); break;
case 'mail_config': mailEnabled = JSON.parse(setting.value).enabled; break;
}
});
db.runSql('INSERT INTO mail (domain, enabled, mailFromValidation, catchAllJson, relayJson) VALUES (?, ?, ?, ?, ?)',
[ domains[0].domain, mailEnabled, mailFromValidation, JSON.stringify(catchAll), JSON.stringify(relay) ], callback);
});
});
};
exports.down = function(db, callback) {
callback();
};
@@ -1,44 +0,0 @@
'use strict';
var async = require('async');
exports.up = function(db, callback) {
db.all('SELECT * FROM users', [ ], function (error, users) {
if (error) return callback(error);
db.all('SELECT * FROM mail WHERE enabled=1', [ ], function (error, mailDomains) {
if (error) return callback(error);
async.series([
db.runSql.bind(db, 'START TRANSACTION;'),
db.runSql.bind(db, 'ALTER TABLE users DROP INDEX users_email'),
db.runSql.bind(db, 'ALTER TABLE users ADD COLUMN fallbackEmail VARCHAR(512) DEFAULT ""'),
function setDefaults(done) {
async.eachSeries(users, function (user, iteratorCallback) {
var defaultEmail = '';
var fallbackEmail = '';
if (mailDomains.length === 0) {
defaultEmail = user.email;
fallbackEmail = user.email;
} else {
defaultEmail = user.username ? (user.username + '@' + mailDomains[0].domain) : user.email;
fallbackEmail = user.email;
}
db.runSql('UPDATE users SET email = ?, fallbackEmail = ? WHERE id = ?', [ defaultEmail, fallbackEmail, user.id ], iteratorCallback);
}, done);
},
db.runSql.bind(db, 'ALTER TABLE users ADD UNIQUE users_email (email)'),
db.runSql.bind(db, 'COMMIT')
], callback);
});
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE users DROP COLUMN fallbackEmail', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,26 +0,0 @@
'use strict';
var async = require('async');
exports.up = function(db, callback) {
db.all('SELECT * FROM settings WHERE name = ?', [ 'tls_config' ], function (error, result) {
if (error) return callback(error);
var tlsConfig = (result[0] && result[0].value) ? JSON.parse(result[0].value) : { provider: 'letsencrypt-prod'};
tlsConfig.provider = tlsConfig.provider.replace(/$le\-/, 'letsencrypt-'); // old cloudrons had le-prod/le-staging
async.series([
db.runSql.bind(db, 'START TRANSACTION;'),
db.runSql.bind(db, 'ALTER TABLE domains ADD COLUMN tlsConfigJson TEXT'),
db.runSql.bind(db, 'UPDATE domains SET tlsConfigJson = ?', [ JSON.stringify(tlsConfig) ]),
db.runSql.bind(db, 'COMMIT')
], callback);
});
};
exports.down = function(db, callback) {
db.runSql('ALTER TABLE domains DROP COLUMN tlsConfigJson', function (error) {
if (error) console.error(error);
callback(error);
});
};
@@ -1,47 +0,0 @@
'use strict';
var async = require('async'),
fs = require('fs'),
superagent = require('superagent');
exports.up = function(db, callback) {
if (!fs.existsSync('/home/yellowtent/configs/cloudron.conf')) {
console.log('Unable to locate cloudron.conf');
return callback();
}
var config = JSON.parse(fs.readFileSync('/home/yellowtent/configs/cloudron.conf', 'utf8'));
if (config.provider !== 'caas' || !config.fqdn) {
console.log('Not caas (%s) or no fqdn', config.provider, config.fqdn);
return callback();
}
db.runSql('SELECT COUNT(*) AS total FROM users', function (error, result) {
if (error) return callback(error);
if (result[0].total === 0) {
console.log('This cloudron is not activated. It will automatically get appstore and caas configs from autoprovision logic');
return callback();
}
console.log('Downloading appstore and caas config');
superagent.get(config.apiServerOrigin + `/api/v1/boxes/${config.fqdn}/config`)
.query({ token: config.token })
.timeout(30 * 1000).end(function (error, result) {
if (error) return callback(error);
console.log('Adding %j config', result.body);
async.series([
db.runSql.bind(db, 'INSERT settings (name, value) VALUES(?, ?)', [ 'appstore_config', JSON.stringify(result.body.appstoreConfig) ]),
db.runSql.bind(db, 'INSERT settings (name, value) VALUES(?, ?)', [ 'caas_config', JSON.stringify(result.body.caasConfig) ])
], callback);
});
});
};
exports.down = function(db, callback) {
callback();
};
@@ -1,24 +0,0 @@
'use strict';
var async = require('async');
exports.up = function(db, callback) {
db.runSql('SELECT * FROM settings WHERE name=?', ['autoupdate_pattern'], function (error, results) {
if (error || results.length === 0) return callback(error); // will use defaults from box code
// migrate the 'daily' update pattern
var appUpdatePattern = results[0].value;
if (appUpdatePattern === '00 00 1,3,5,23 * * *') appUpdatePattern = '00 30 1,3,5,23 * * *';
async.series([
db.runSql.bind(db, 'START TRANSACTION;'),
db.runSql.bind(db, 'DELETE FROM settings WHERE name=?', ['autoupdate_pattern']),
db.runSql.bind(db, 'INSERT settings (name, value) VALUES(?, ?)', ['app_autoupdate_pattern', appUpdatePattern]),
db.runSql.bind(db, 'COMMIT')
], callback);
});
};
exports.down = function(db, callback) {
callback();
};

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