Files
speckle-server/utils/1click_image_scripts/setup.py
T
andrewwallacespeckle ff6433128a FE2 - Embedding (#1979)
* Add Dialog

* Add options to embed dialog

* Min Height of Clipboard Input multiline to 3 lines

* Check for visibility

* Link to change access of project

* Rename to guided mode

* Change icon when user clicks copy button

* Update Menu styles based on agi feedback

* Update graphql.ts

* Embed Options as hashState

* Auto grow Clipboard Input

* embed state and more options

* Tidyups

* Footer only shows when !embedOptions.isTransparent

* Add auto/manual Load

* Add Pre setup component

* WIP Button Group mobile

* Updates around manual load

* Viewer Share nav

* Add embed dialog to project page

* Minor fixes

* Check for federated

* Responsive Tidyups

* Responsive Fixes. Fix console issues

* Add Alert to Version Embed

* Disable Zoom

* GQL updates

* Comment Slideshow

* GraphQl changes

* Fix visibility

* Build fix

* Revert "Build fix"

This reverts commit 0e706cbd9fde78204032bb1ec4421b1742d023ac.

* remove unneeded change, revert yarn.lock

* Test Commit

* Remove commit test

* Fix build

* Update Tailwind. Add base url env

* fix for portal scope issue

* useLogger

* useLogger

* chore(fe2): include NUXT_PUBLIC_BASE_URL in deployment manifests

* lazy load optimization

* lint fixes

* Updates

* Re-add guided open Dialog sections

* Prevent login popup on embed

* Tidy up mobile combined button group

* Tidy up embed Dialogs

* Small styling issues

* Update scrolling in embed dialog

* Move selection info when embed

* Testing fixes

* Discuss in Speckle

* Responsive Dialog Changes

* Fix bug

* WIP Manual Load

* Fix nuxt errors

* Fix nuxt logger issue

* Fix embed dialog overflows

* New Dialog layout

* Responsive Breakpoint change

* Preview Image

* Fix bug with dialogSection

* Hide selection info on mobile when thread is open

* Footer Model Name

* Overflow on ClipboardInput

* Style fixes

* Tidy ups

* Responsive updates

* Responsive fixes

* Update button

* Changes from testing

* Fix embed height with footer

* Fix Dialog Section

* Fixes from testing

* Move "reset filters" on embed

* Small fixes

* Updates from CR 1

* CR Comments 2

* Updates from CR

* Add deserializeEmbedOptions helper

* DialogSection changes

* Revert changes in TextArea

* Updates from CR

* Only check for noscroll in watch

* Update useRoute

* Comment Slideshow mode

* Changes from testing

* Fix mobile share button

* onMounted warn fixes

* Updates from testing

* Remove nesting of ManualLoad

* Keep Speckle text on mobile

* minor cleanup & bugfixes

* Add target prop to Logo

* navbar flash fix + more cleanup

* Fix urls

* Footer Logo changes

* Remove viewer-transparent from layout

* Add Reply in Speckle

* Remove Anchored Points from embed

* Final changes pre CR

* Fix Anchored Points

* Update packages/frontend-2/components/project/model-page/dialog/embed/Embed.vue

Co-authored-by: Kristaps Fabians Geikins <fabians@speckle.systems>

* Fixes from CR

* Updates from cr

* Changes WIP

* Fix for dialog opening

* Changes from PR

* Updates to check embed in activity

* fix(fe2): project settings dialog error

* Make Team open section on click of "Manage"

* Fixes from merge

* Changes from cr

* Compare old to new in watch

* Fix logo in footer of embed

* Fixes from merge

* Fix build. Fix lazy load

* Updates from Benjamin

* Fix transparent bg

---------

Co-authored-by: Kristaps Fabians Geikins <fabis94@live.com>
Co-authored-by: Iain Sproat <68657+iainsproat@users.noreply.github.com>
Co-authored-by: Kristaps Fabians Geikins <fabians@speckle.systems>
2024-02-06 10:38:22 +00:00

226 lines
7.6 KiB
Python
Executable File

#!/usr/bin/env python3
import os
import socket
import subprocess
import secrets
import ruamel.yaml # this module preserves yaml comments and whitespaces
from ruamel.yaml.scalarstring import DoubleQuotedScalarString
FILE_PATH = os.path.dirname(os.path.abspath(__file__))
LOGO_STR = """
_____ _ _ _____
/ ___| | | | | / ___|
\ `--. _ __ ___ ___| | _| | ___\ `--. ___ _ ____ _____ _ __
`--. \ '_ \ / _ \/ __| |/ / |/ _ \`--. \/ _ \ '__\ \ / / _ \ '__|
/\__/ / |_) | __/ (__| <| | __/\__/ / __/ | \ V / __/ |
\____/| .__/ \___|\___|_|\_\_|\___\____/ \___|_| \_/ \___|_|
| |
|_|
"""
def get_local_ip():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
ip = s.getsockname()[0]
s.close()
if not ip:
print("Error: Can't get local IP address")
exit(1)
return ip
def read_domain(ip):
print("\nYou can set up a domain name for this Speckle server.")
print(
"Important: To use a domain name, you must first configure it to point to this VM address (so we can issue the SSL certificate)"
)
print(f"VM address: {ip}")
while True:
domain = input("Domain name (leave blank to use the IP address): ").strip()
if not domain:
return None
try:
domain_ip = socket.gethostbyname(domain.strip())
except Exception as ex:
print(f"Error: Domain '{domain}' cannot be resolved: {str(ex)}")
continue
if domain_ip != ip:
print(f"Error: Domain '{domain}' points to {domain_ip} instead of {ip}")
continue
return domain
def read_email_settings(domain):
print(
"\nYou should configure an email provider to allow the Speckle Server to send emails."
)
print(
"Supported vendors: Any email provider that can provide SMTP connection details (mailjet, mailgun, etc)."
)
print(
"Important: If you don't configure email details, some features that require sending emails will not work, nevertheless the server should be functional."
)
while True:
enable_email = False
while True:
enable_email = input("Enable emails? [Y/n]: ").strip().lower()
if enable_email in ["n", "no"]:
enable_email = False
break
elif enable_email in ["", "y", "yes"]:
enable_email = True
break
else:
print("Unrecognized option")
continue
if not enable_email:
return None
print("Enter your SMTP connection details offered by your email provider")
smtp_host = input("SMTP server / host: ").strip()
smtp_port = input("SMTP port: ").strip()
try:
int(smtp_port)
except Exception:
print("Error: SMTP port must be a number. Retrying...")
continue
smtp_user = input("SMTP Username: ").strip()
smtp_pass = input("SMTP Password: ").strip()
if domain:
default_from_email = "no-reply@" + domain
else:
default_from_email = ""
email_from = input(f"Email address to send email as [{default_from_email}]: ")
if not email_from.strip():
email_from = default_from_email
if (
not smtp_host
or not smtp_port
or not smtp_user
or not smtp_pass
or not email_from
):
print("Error: One or more fields were empty. Retrying...")
continue
return {
"host": smtp_host,
"port": smtp_port,
"user": smtp_user,
"pass": smtp_pass,
"from": email_from,
}
def main():
print(LOGO_STR)
ip = get_local_ip()
###
### Read user input
#########
domain = read_domain(ip)
if domain:
canonical_url = f"https://{domain}"
else:
canonical_url = f"http://{ip}"
email = read_email_settings(domain)
###
### Create docker-compose.yml from the template
#########
print("\nConfiguring docker containers...")
yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
with open(os.path.join(FILE_PATH, "template-docker-compose.yml"), "r") as f:
yml_doc = yaml.load(f)
env = yml_doc["services"]["speckle-server"]["environment"]
env["CANONICAL_URL"] = DoubleQuotedScalarString(canonical_url)
env["FRONTEND_ORIGIN"] = DoubleQuotedScalarString(canonical_url)
env["SESSION_SECRET"] = DoubleQuotedScalarString(secrets.token_hex(32))
if email:
env["EMAIL"] = DoubleQuotedScalarString("true")
env["EMAIL_HOST"] = DoubleQuotedScalarString(email["host"])
env["EMAIL_PORT"] = DoubleQuotedScalarString(email["port"])
env["EMAIL_USERNAME"] = DoubleQuotedScalarString(email["user"])
env["EMAIL_PASSWORD"] = DoubleQuotedScalarString(email["pass"])
env["EMAIL_FROM"] = DoubleQuotedScalarString(email["from"])
else:
env["EMAIL"] = DoubleQuotedScalarString("false")
fe2env = yml_doc["services"]["speckle-frontend-2"]["environment"]
fe2env["NUXT_PUBLIC_SERVER_NAME"] = DoubleQuotedScalarString(canonical_url)
fe2env["NUXT_PUBLIC_API_ORIGIN"] = DoubleQuotedScalarString(canonical_url)
fe2env["NUXT_PUBLIC_BASE_URL"] = DoubleQuotedScalarString(canonical_url)
with open(os.path.join(FILE_PATH, "docker-compose.yml"), "w") as f:
f.write("# This file was generated by SpeckleServer setup.\n")
f.write("# If the setup is re-run, this file will be overwritten.\n\n")
yaml.dump(yml_doc, f)
###
### Run the new docker compose file (will update containers if already running)
#########
subprocess.run(
["bash", "-c", f'cd "{FILE_PATH}"; docker compose up -d'], check=True
)
###
### Update nginx config and restart nginx
#########
print("\nConfiguring local nginx...")
nginx_conf_str = "# This file is managed by SpeckleServer setup script.\n"
nginx_conf_str += (
"# Any modifications will be removed when the setup script is re-executed\n\n"
)
with open(os.path.join(FILE_PATH, "template-nginx-site.conf"), "r") as f:
nginx_conf_str += f.read()
if domain:
nginx_conf_str = nginx_conf_str.replace("TODO_REPLACE_WITH_SERVER_NAME", domain)
else:
nginx_conf_str = nginx_conf_str.replace("TODO_REPLACE_WITH_SERVER_NAME", "_")
with open("/etc/nginx/sites-available/speckle-server", "w") as f:
f.write(nginx_conf_str)
subprocess.run(["nginx", "-s", "reload"], check=True)
###
### Run letsencrypt on new config
#########
if domain:
print("\n***")
print(
"*** Will now run LetsEncrypt utility to generate https certificate. Please answer any questions that are presented"
)
print(
"*** We highly recommend setting a good email address so that you are notified if there is any action needed to renew certificates"
)
print("***")
subprocess.run(["certbot", "--nginx", "-d", domain])
print("\nConfiguration complete!")
print("You can access your speckle server at: " + canonical_url)
print(LOGO_STR)
print("\nOne more thing and you are ready to roll:")
print(
f" - Go to {canonical_url} in your browser and create an account. The first user to register will be granted administrator rights."
)
print(
" - Fill in information about your server under your profile page (in the lower left corner)."
)
print("\nHappy Speckling!")
if __name__ == "__main__":
main()