mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-28 03:50:10 +00:00
Compare commits
2 Commits
8672d7dc18
...
82d07e423c
Author | SHA1 | Date | |
---|---|---|---|
82d07e423c | |||
8e6cf799cd |
@ -12,9 +12,9 @@ before:
|
|||||||
- python3 config/fixconfig.py -i config/config-base.json -o data/config-base.json
|
- python3 config/fixconfig.py -i config/config-base.json -o data/config-base.json
|
||||||
- python3 config/generate_ini.py -i config/config-base.json -o data/config-default.ini
|
- python3 config/generate_ini.py -i config/config-base.json -o data/config-default.ini
|
||||||
- python3 -m pip install libsass
|
- python3 -m pip install libsass
|
||||||
- python3 scss/get_node_deps.py
|
- npm install
|
||||||
- python3 scss/compile.py -y
|
- python3 scss/compile.py
|
||||||
- python3 mail/generate.py -y
|
- python3 mail/generate.py
|
||||||
- python3 version.py {{.Version}} version.go
|
- python3 version.py {{.Version}} version.go
|
||||||
- bash -c 'npx esbuild ts/* --outdir=data/static --minify'
|
- bash -c 'npx esbuild ts/* --outdir=data/static --minify'
|
||||||
- go get -u github.com/swaggo/swag/cmd/swag
|
- go get -u github.com/swaggo/swag/cmd/swag
|
||||||
|
@ -6,7 +6,7 @@ RUN apt update -y \
|
|||||||
&& apt install build-essential python3-pip curl software-properties-common sed upx -y \
|
&& apt install build-essential python3-pip curl software-properties-common sed upx -y \
|
||||||
&& (curl -sL https://deb.nodesource.com/setup_14.x | bash -) \
|
&& (curl -sL https://deb.nodesource.com/setup_14.x | bash -) \
|
||||||
&& apt install nodejs \
|
&& apt install nodejs \
|
||||||
&& (cd /opt/build; make headless; make compress) \
|
&& (cd /opt/build; make all; make compress) \
|
||||||
&& sed -i 's#id="pwrJfPath" placeholder="Folder"#id="pwrJfPath" value="/jf" disabled#g' /opt/build/build/data/templates/setup.html
|
&& sed -i 's#id="pwrJfPath" placeholder="Folder"#id="pwrJfPath" value="/jf" disabled#g' /opt/build/build/data/templates/setup.html
|
||||||
|
|
||||||
FROM golang:latest
|
FROM golang:latest
|
||||||
|
22
Makefile
22
Makefile
@ -8,23 +8,11 @@ sass:
|
|||||||
$(info Getting libsass)
|
$(info Getting libsass)
|
||||||
python3 -m pip install libsass
|
python3 -m pip install libsass
|
||||||
$(info Getting node dependencies)
|
$(info Getting node dependencies)
|
||||||
python3 scss/get_node_deps.py
|
npm install
|
||||||
$(info Compiling sass)
|
$(info Compiling sass)
|
||||||
python3 scss/compile.py
|
python3 scss/compile.py
|
||||||
|
|
||||||
sass-headless:
|
email:
|
||||||
$(info Getting libsass)
|
|
||||||
python3 -m pip install libsass
|
|
||||||
$(info Getting node dependencies)
|
|
||||||
python3 scss/get_node_deps.py
|
|
||||||
$(info Compiling sass)
|
|
||||||
python3 scss/compile.py -y
|
|
||||||
|
|
||||||
mail-headless:
|
|
||||||
$(info Generating email html)
|
|
||||||
python3 mail/generate.py -y
|
|
||||||
|
|
||||||
mail:
|
|
||||||
$(info Generating email html)
|
$(info Generating email html)
|
||||||
python3 mail/generate.py
|
python3 mail/generate.py
|
||||||
|
|
||||||
@ -62,8 +50,4 @@ copy:
|
|||||||
install:
|
install:
|
||||||
cp -r build $(DESTDIR)/jfa-go
|
cp -r build $(DESTDIR)/jfa-go
|
||||||
|
|
||||||
all: configuration sass mail version typescript swagger compile copy
|
all: configuration sass email version typescript swagger compile copy
|
||||||
headless: configuration sass-headless mail-headless version typescript swagger compile copy
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -628,6 +628,14 @@
|
|||||||
"type": "text",
|
"type": "text",
|
||||||
"value": "",
|
"value": "",
|
||||||
"description": "Location of custom bootstrap CSS."
|
"description": "Location of custom bootstrap CSS."
|
||||||
|
},
|
||||||
|
"html_templates": {
|
||||||
|
"name": "Custom HTML Template Directory",
|
||||||
|
"required": false,
|
||||||
|
"requires_restart": true,
|
||||||
|
"type": "text",
|
||||||
|
"value": "",
|
||||||
|
"description": "Path to directory containing custom versions of web ui pages. See wiki for more info."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,6 @@ import json
|
|||||||
import argparse
|
import argparse
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("-i", "--input", help="input config base from jf-accounts")
|
|
||||||
parser.add_argument("-o", "--output", help="output ini")
|
|
||||||
|
|
||||||
|
|
||||||
def generate_ini(base_file, ini_file):
|
def generate_ini(base_file, ini_file):
|
||||||
"""
|
"""
|
||||||
@ -36,6 +32,11 @@ def generate_ini(base_file, ini_file):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("-i", "--input", help="input config base from jf-accounts")
|
||||||
|
parser.add_argument("-o", "--output", help="output ini")
|
||||||
|
|
||||||
print(generate_ini(base_file=args.input, ini_file=args.output))
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
print(generate_ini(base_file=args.input, ini_file=args.output))
|
||||||
|
@ -1,738 +0,0 @@
|
|||||||
{
|
|
||||||
"order": [
|
|
||||||
"jellyfin",
|
|
||||||
"ui",
|
|
||||||
"password_validation",
|
|
||||||
"email",
|
|
||||||
"password_resets",
|
|
||||||
"invite_emails",
|
|
||||||
"notifications",
|
|
||||||
"mailgun",
|
|
||||||
"smtp",
|
|
||||||
"ombi",
|
|
||||||
"deletion",
|
|
||||||
"files"
|
|
||||||
],
|
|
||||||
"jellyfin": {
|
|
||||||
"order": [
|
|
||||||
"username",
|
|
||||||
"password",
|
|
||||||
"server",
|
|
||||||
"public_server",
|
|
||||||
"client"
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "Jellyfin",
|
|
||||||
"description": "Settings for connecting to Jellyfin"
|
|
||||||
},
|
|
||||||
"username": {
|
|
||||||
"name": "Jellyfin Username",
|
|
||||||
"required": true,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "text",
|
|
||||||
"value": "username",
|
|
||||||
"description": "It is recommended to create a limited admin account for this program."
|
|
||||||
},
|
|
||||||
"password": {
|
|
||||||
"name": "Jellyfin Password",
|
|
||||||
"required": true,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "password",
|
|
||||||
"value": "password"
|
|
||||||
},
|
|
||||||
"server": {
|
|
||||||
"name": "Server address",
|
|
||||||
"required": true,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "text",
|
|
||||||
"value": "http://jellyfin.local:8096",
|
|
||||||
"description": "Jellyfin server address. Can be public, or local for security purposes."
|
|
||||||
},
|
|
||||||
"public_server": {
|
|
||||||
"name": "Public address",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"type": "text",
|
|
||||||
"value": "https://jellyf.in:443",
|
|
||||||
"description": "Publicly accessible Jellyfin address for invite form. Leave blank to reuse the above address."
|
|
||||||
},
|
|
||||||
"client": {
|
|
||||||
"name": "Client Name",
|
|
||||||
"required": true,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "text",
|
|
||||||
"value": "jfa-go",
|
|
||||||
"description": "The name of the client that will show up in the Jellyfin dashboard."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ui": {
|
|
||||||
"order": [
|
|
||||||
"theme",
|
|
||||||
"host",
|
|
||||||
"port",
|
|
||||||
"jellyfin_login",
|
|
||||||
"admin_only",
|
|
||||||
"username",
|
|
||||||
"password",
|
|
||||||
"email",
|
|
||||||
"debug",
|
|
||||||
"contact_message",
|
|
||||||
"help_message",
|
|
||||||
"success_message",
|
|
||||||
"bs5"
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "General",
|
|
||||||
"description": "Settings related to the UI and program functionality."
|
|
||||||
},
|
|
||||||
"theme": {
|
|
||||||
"name": "Default Look",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "select",
|
|
||||||
"options": [
|
|
||||||
"Bootstrap (Light)",
|
|
||||||
"Jellyfin (Dark)",
|
|
||||||
"Custom CSS"
|
|
||||||
],
|
|
||||||
"value": "Jellyfin (Dark)",
|
|
||||||
"description": "Default appearance for all users."
|
|
||||||
},
|
|
||||||
"host": {
|
|
||||||
"name": "Address",
|
|
||||||
"required": true,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "text",
|
|
||||||
"value": "0.0.0.0",
|
|
||||||
"description": "Set 0.0.0.0 to run on localhost"
|
|
||||||
},
|
|
||||||
"port": {
|
|
||||||
"name": "Port",
|
|
||||||
"required": true,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "number",
|
|
||||||
"value": 8056
|
|
||||||
},
|
|
||||||
"jellyfin_login": {
|
|
||||||
"name": "Use Jellyfin for authentication",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "bool",
|
|
||||||
"value": true,
|
|
||||||
"description": "Enable this to use Jellyfin users instead of the below username and pw."
|
|
||||||
},
|
|
||||||
"admin_only": {
|
|
||||||
"name": "Allow admin users only",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": true,
|
|
||||||
"depends_true": "jellyfin_login",
|
|
||||||
"type": "bool",
|
|
||||||
"value": true,
|
|
||||||
"description": "Allows only admin users on Jellyfin to access the admin page."
|
|
||||||
},
|
|
||||||
"username": {
|
|
||||||
"name": "Web Username",
|
|
||||||
"required": true,
|
|
||||||
"requires_restart": true,
|
|
||||||
"depends_false": "jellyfin_login",
|
|
||||||
"type": "text",
|
|
||||||
"value": "your username",
|
|
||||||
"description": "Username for admin page (Leave blank if using jellyfin_login)"
|
|
||||||
},
|
|
||||||
"password": {
|
|
||||||
"name": "Web Password",
|
|
||||||
"required": true,
|
|
||||||
"requires_restart": true,
|
|
||||||
"depends_false": "jellyfin_login",
|
|
||||||
"type": "password",
|
|
||||||
"value": "your password",
|
|
||||||
"description": "Password for admin page (Leave blank if using jellyfin_login)"
|
|
||||||
},
|
|
||||||
"email": {
|
|
||||||
"name": "Admin email address",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_false": "jellyfin_login",
|
|
||||||
"type": "text",
|
|
||||||
"value": "example@example.com",
|
|
||||||
"description": "Address to send notifications to (Leave blank if using jellyfin_login)"
|
|
||||||
},
|
|
||||||
"debug": {
|
|
||||||
"name": "Debug logging",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "bool",
|
|
||||||
"value": false,
|
|
||||||
"description": "Enables debug logging and exposes pprof as a route (Don't use in production!)"
|
|
||||||
},
|
|
||||||
"contact_message": {
|
|
||||||
"name": "Contact message",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"type": "text",
|
|
||||||
"value": "Need help? contact me.",
|
|
||||||
"description": "Displayed at bottom of all pages except admin"
|
|
||||||
},
|
|
||||||
"help_message": {
|
|
||||||
"name": "Help message",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"type": "text",
|
|
||||||
"value": "Enter your details to create an account.",
|
|
||||||
"description": "Displayed at top of invite form."
|
|
||||||
},
|
|
||||||
"success_message": {
|
|
||||||
"name": "Success message",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"type": "text",
|
|
||||||
"value": "Your account has been created. Click below to continue to Jellyfin.",
|
|
||||||
"description": "Displayed when a user creates an account"
|
|
||||||
},
|
|
||||||
"bs5": {
|
|
||||||
"name": "Use Bootstrap 5",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "bool",
|
|
||||||
"value": false,
|
|
||||||
"description": "Use Bootstrap 5 (currently in alpha). This also removes the need for jQuery, so the page should load faster."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"password_validation": {
|
|
||||||
"order": [
|
|
||||||
"enabled",
|
|
||||||
"min_length",
|
|
||||||
"upper",
|
|
||||||
"lower",
|
|
||||||
"number",
|
|
||||||
"special"
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "Password Validation",
|
|
||||||
"description": "Password validation (minimum length, etc.)"
|
|
||||||
},
|
|
||||||
"enabled": {
|
|
||||||
"name": "Enabled",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"type": "bool",
|
|
||||||
"value": true
|
|
||||||
},
|
|
||||||
"min_length": {
|
|
||||||
"name": "Minimum Length",
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "enabled",
|
|
||||||
"type": "text",
|
|
||||||
"value": "8"
|
|
||||||
},
|
|
||||||
"upper": {
|
|
||||||
"name": "Minimum uppercase characters",
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "enabled",
|
|
||||||
"type": "text",
|
|
||||||
"value": "1"
|
|
||||||
},
|
|
||||||
"lower": {
|
|
||||||
"name": "Minimum lowercase characters",
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "enabled",
|
|
||||||
"type": "text",
|
|
||||||
"value": "0"
|
|
||||||
},
|
|
||||||
"number": {
|
|
||||||
"name": "Minimum number count",
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "enabled",
|
|
||||||
"type": "text",
|
|
||||||
"value": "1"
|
|
||||||
},
|
|
||||||
"special": {
|
|
||||||
"name": "Minimum number of special characters",
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "enabled",
|
|
||||||
"type": "text",
|
|
||||||
"value": "0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"email": {
|
|
||||||
"order": [
|
|
||||||
"no_username",
|
|
||||||
"use_24h",
|
|
||||||
"date_format",
|
|
||||||
"message",
|
|
||||||
"method",
|
|
||||||
"address",
|
|
||||||
"from"
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "Email",
|
|
||||||
"description": "General email settings. Ignore if not using email features."
|
|
||||||
},
|
|
||||||
"no_username": {
|
|
||||||
"name": "Use email addresses as username",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "method",
|
|
||||||
"type": "bool",
|
|
||||||
"value": false,
|
|
||||||
"description": "Use email address from invite form as username on Jellyfin."
|
|
||||||
},
|
|
||||||
"use_24h": {
|
|
||||||
"name": "Use 24h time",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "method",
|
|
||||||
"type": "bool",
|
|
||||||
"value": true
|
|
||||||
},
|
|
||||||
"date_format": {
|
|
||||||
"name": "Date format",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "method",
|
|
||||||
"type": "text",
|
|
||||||
"value": "%d/%m/%y",
|
|
||||||
"description": "Date format used in emails. Follows datetime.strftime format."
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"name": "Help message",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "method",
|
|
||||||
"type": "text",
|
|
||||||
"value": "Need help? contact me.",
|
|
||||||
"description": "Message displayed at bottom of emails."
|
|
||||||
},
|
|
||||||
"method": {
|
|
||||||
"name": "Email method",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"type": "select",
|
|
||||||
"options": [
|
|
||||||
"smtp",
|
|
||||||
"mailgun"
|
|
||||||
],
|
|
||||||
"value": "smtp",
|
|
||||||
"description": "Method of sending email to use."
|
|
||||||
},
|
|
||||||
"address": {
|
|
||||||
"name": "Sent from (address)",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "method",
|
|
||||||
"type": "email",
|
|
||||||
"value": "jellyfin@jellyf.in",
|
|
||||||
"description": "Address to send emails from"
|
|
||||||
},
|
|
||||||
"from": {
|
|
||||||
"name": "Sent from (name)",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "method",
|
|
||||||
"type": "text",
|
|
||||||
"value": "Jellyfin",
|
|
||||||
"description": "The name of the sender"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"password_resets": {
|
|
||||||
"order": [
|
|
||||||
"enabled",
|
|
||||||
"watch_directory",
|
|
||||||
"email_html",
|
|
||||||
"email_text",
|
|
||||||
"subject"
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "Password Resets",
|
|
||||||
"description": "Settings for the password reset handler."
|
|
||||||
},
|
|
||||||
"enabled": {
|
|
||||||
"name": "Enabled",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "bool",
|
|
||||||
"value": true,
|
|
||||||
"description": "Enable to store provided email addresses, monitor Jellyfin directory for pw-resets, and send reset pins"
|
|
||||||
},
|
|
||||||
"watch_directory": {
|
|
||||||
"name": "Jellyfin directory",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": true,
|
|
||||||
"depends_true": "enabled",
|
|
||||||
"type": "text",
|
|
||||||
"value": "/path/to/jellyfin",
|
|
||||||
"description": "Path to the folder Jellyfin puts password-reset files."
|
|
||||||
},
|
|
||||||
"email_html": {
|
|
||||||
"name": "Custom email (HTML)",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "enabled",
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"description": "Path to custom email html"
|
|
||||||
},
|
|
||||||
"email_text": {
|
|
||||||
"name": "Custom email (plaintext)",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "enabled",
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"description": "Path to custom email in plain text"
|
|
||||||
},
|
|
||||||
"subject": {
|
|
||||||
"name": "Email subject",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "enabled",
|
|
||||||
"type": "text",
|
|
||||||
"value": "Password Reset - Jellyfin",
|
|
||||||
"description": "Subject of password reset emails."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"invite_emails": {
|
|
||||||
"order": [
|
|
||||||
"enabled",
|
|
||||||
"email_html",
|
|
||||||
"email_text",
|
|
||||||
"subject",
|
|
||||||
"url_base"
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "Invite emails",
|
|
||||||
"description": "Settings for sending invites directly to users."
|
|
||||||
},
|
|
||||||
"enabled": {
|
|
||||||
"name": "Enabled",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"type": "bool",
|
|
||||||
"value": true
|
|
||||||
},
|
|
||||||
"email_html": {
|
|
||||||
"name": "Custom email (HTML)",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "enabled",
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"description": "Path to custom email HTML"
|
|
||||||
},
|
|
||||||
"email_text": {
|
|
||||||
"name": "Custom email (plaintext)",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "enabled",
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"description": "Path to custom email in plain text"
|
|
||||||
},
|
|
||||||
"subject": {
|
|
||||||
"name": "Email subject",
|
|
||||||
"required": true,
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "enabled",
|
|
||||||
"type": "text",
|
|
||||||
"value": "Invite - Jellyfin",
|
|
||||||
"description": "Subject of invite emails."
|
|
||||||
},
|
|
||||||
"url_base": {
|
|
||||||
"name": "URL Base",
|
|
||||||
"required": true,
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "enabled",
|
|
||||||
"type": "text",
|
|
||||||
"value": "http://accounts.jellyf.in:8056/invite",
|
|
||||||
"description": "Base URL for jfa-go. This is necessary because using a reverse proxy means the program has no way of knowing the URL itself."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notifications": {
|
|
||||||
"order": [
|
|
||||||
"enabled",
|
|
||||||
"expiry_html",
|
|
||||||
"expiry_text",
|
|
||||||
"created_html",
|
|
||||||
"created_text"
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "Notifications",
|
|
||||||
"description": "Notification related settings."
|
|
||||||
},
|
|
||||||
"enabled": {
|
|
||||||
"name": "Enabled",
|
|
||||||
"required": "false",
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "bool",
|
|
||||||
"value": true,
|
|
||||||
"description": "Enabling adds optional toggles to invites to notify on expiry and user creation."
|
|
||||||
},
|
|
||||||
"expiry_html": {
|
|
||||||
"name": "Expiry email (HTML)",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "enabled",
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"description": "Path to expiry notification email HTML."
|
|
||||||
},
|
|
||||||
"expiry_text": {
|
|
||||||
"name": "Expiry email (Plaintext)",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": "false",
|
|
||||||
"depends_true": "enabled",
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"description": "Path to expiry notification email in plaintext."
|
|
||||||
},
|
|
||||||
"created_html": {
|
|
||||||
"name": "User created email (HTML)",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "enabled",
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"description": "Path to user creation notification email HTML."
|
|
||||||
},
|
|
||||||
"created_text": {
|
|
||||||
"name": "User created email (Plaintext)",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"depends_true": "enabled",
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"description": "Path to user creation notification email in plaintext."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"mailgun": {
|
|
||||||
"order": [
|
|
||||||
"api_url",
|
|
||||||
"api_key"
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "Mailgun (Email)",
|
|
||||||
"description": "Mailgun API connection settings"
|
|
||||||
},
|
|
||||||
"api_url": {
|
|
||||||
"name": "API URL",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"type": "text",
|
|
||||||
"value": "https://api.mailgun.net..."
|
|
||||||
},
|
|
||||||
"api_key": {
|
|
||||||
"name": "API Key",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"type": "text",
|
|
||||||
"value": "your api key"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"smtp": {
|
|
||||||
"order": [
|
|
||||||
"username",
|
|
||||||
"encryption",
|
|
||||||
"server",
|
|
||||||
"port",
|
|
||||||
"password"
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "SMTP (Email)",
|
|
||||||
"description": "SMTP Server connection settings."
|
|
||||||
},
|
|
||||||
"username": {
|
|
||||||
"name": "Username",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"description": "Username for SMTP. Leave blank to user send from address as username."
|
|
||||||
},
|
|
||||||
"encryption": {
|
|
||||||
"name": "Encryption Method",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"type": "select",
|
|
||||||
"options": [
|
|
||||||
"ssl_tls",
|
|
||||||
"starttls"
|
|
||||||
],
|
|
||||||
"value": "starttls",
|
|
||||||
"description": "Your email provider should provide different ports for each encryption method. Generally 465 for ssl_tls, 587 for starttls."
|
|
||||||
},
|
|
||||||
"server": {
|
|
||||||
"name": "Server address",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"type": "text",
|
|
||||||
"value": "smtp.jellyf.in",
|
|
||||||
"description": "SMTP Server address."
|
|
||||||
},
|
|
||||||
"port": {
|
|
||||||
"name": "Port",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"type": "number",
|
|
||||||
"value": 465
|
|
||||||
},
|
|
||||||
"password": {
|
|
||||||
"name": "Password",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"type": "password",
|
|
||||||
"value": "smtp password"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ombi": {
|
|
||||||
"order": [
|
|
||||||
"enabled",
|
|
||||||
"server",
|
|
||||||
"api_key"
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "Ombi Integration",
|
|
||||||
"description": "Connect to Ombi to automatically create a new user's account. You'll need to create an Ombi user template."
|
|
||||||
},
|
|
||||||
"enabled": {
|
|
||||||
"name": "Enabled",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "bool",
|
|
||||||
"value": false,
|
|
||||||
"description": "Enable to create an Ombi account for new Jellyfin users"
|
|
||||||
},
|
|
||||||
"server": {
|
|
||||||
"name": "URL",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "text",
|
|
||||||
"value": "localhost:5000",
|
|
||||||
"depends_true": "enabled",
|
|
||||||
"description": "Ombi server URL, including http(s)://."
|
|
||||||
},
|
|
||||||
"api_key": {
|
|
||||||
"name": "API Key",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"depends_true": "enabled",
|
|
||||||
"description": "API Key. Get this from the first tab in Ombi settings."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"deletion": {
|
|
||||||
"order": [
|
|
||||||
"subject",
|
|
||||||
"email_html",
|
|
||||||
"email_text"
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "Account Deletion",
|
|
||||||
"description": "Subject/email files for account deletion emails."
|
|
||||||
},
|
|
||||||
"subject": {
|
|
||||||
"name": "Email subject",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"type": "text",
|
|
||||||
"value": "Your account was deleted - Jellyfin",
|
|
||||||
"description": "Subject of account deletion emails."
|
|
||||||
},
|
|
||||||
"email_html": {
|
|
||||||
"name": "Custom email (HTML)",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"description": "Path to custom email html"
|
|
||||||
},
|
|
||||||
"email_text": {
|
|
||||||
"name": "Custom email (plaintext)",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"description": "Path to custom email in plain text"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"files": {
|
|
||||||
"order": [
|
|
||||||
"invites",
|
|
||||||
"emails",
|
|
||||||
"ombi_template",
|
|
||||||
"user_template",
|
|
||||||
"user_configuration",
|
|
||||||
"user_displayprefs",
|
|
||||||
"user_profiles",
|
|
||||||
"custom_css"
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "File Storage",
|
|
||||||
"description": "Optional settings for changing storage locations."
|
|
||||||
},
|
|
||||||
"invites": {
|
|
||||||
"name": "Invite Storage",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"description": "Location of stored invites (json)."
|
|
||||||
},
|
|
||||||
"emails": {
|
|
||||||
"name": "Email Addresses",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"description": "Location of stored email addresses (json)."
|
|
||||||
},
|
|
||||||
"ombi_template": {
|
|
||||||
"name": "Ombi user template",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": false,
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"description": "Location of stored Ombi user template."
|
|
||||||
},
|
|
||||||
"user_template": {
|
|
||||||
"name": "User Template",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"description": "Deprecated. Location of stored user policy template (json)."
|
|
||||||
},
|
|
||||||
"user_configuration": {
|
|
||||||
"name": "userConfiguration",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"description": "Deprecated. Location of stored user configuration template (used for setting homescreen layout) (json)"
|
|
||||||
},
|
|
||||||
"user_displayprefs": {
|
|
||||||
"name": "displayPreferences",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"description": "Deprecated. Location of stored displayPreferences template (also used for homescreen layout) (json)"
|
|
||||||
},
|
|
||||||
"user_profiles": {
|
|
||||||
"name": "User Profiles",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"description": "Location of stored user profiles (encompasses template and configuration and displayprefs) (json)"
|
|
||||||
},
|
|
||||||
"custom_css": {
|
|
||||||
"name": "Custom CSS",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"description": "Location of custom bootstrap CSS."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
6
go.mod
6
go.mod
@ -31,12 +31,12 @@ require (
|
|||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14
|
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14
|
||||||
github.com/swaggo/gin-swagger v1.2.0
|
github.com/swaggo/gin-swagger v1.2.0
|
||||||
github.com/swaggo/swag v1.6.7 // indirect
|
github.com/swaggo/swag v1.6.8 // indirect
|
||||||
github.com/ugorji/go v1.1.9 // indirect
|
github.com/ugorji/go v1.1.9 // indirect
|
||||||
github.com/urfave/cli/v2 v2.2.0 // indirect
|
github.com/urfave/cli/v2 v2.2.0 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect
|
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect
|
||||||
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 // indirect
|
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0 // indirect
|
||||||
golang.org/x/tools v0.0.0-20201008184944-d01b322e6f06 // indirect
|
golang.org/x/tools v0.0.0-20201017001424-6003fad69a88 // indirect
|
||||||
google.golang.org/protobuf v1.25.0 // indirect
|
google.golang.org/protobuf v1.25.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.61.0
|
gopkg.in/ini.v1 v1.61.0
|
||||||
gopkg.in/yaml.v2 v2.3.0 // indirect
|
gopkg.in/yaml.v2 v2.3.0 // indirect
|
||||||
|
12
go.sum
12
go.sum
@ -88,6 +88,7 @@ github.com/go-playground/validator/v10 v10.3.0 h1:nZU+7q+yJoFmwvNgv/LnPUkwPal62+
|
|||||||
github.com/go-playground/validator/v10 v10.3.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
github.com/go-playground/validator/v10 v10.3.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||||
github.com/go-playground/validator/v10 v10.4.0 h1:72qIR/m8ybvL8L5TIyfgrigqkrw7kVYAvjEvpT85l70=
|
github.com/go-playground/validator/v10 v10.4.0 h1:72qIR/m8ybvL8L5TIyfgrigqkrw7kVYAvjEvpT85l70=
|
||||||
github.com/go-playground/validator/v10 v10.4.0/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
github.com/go-playground/validator/v10 v10.4.0/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||||
|
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
@ -199,6 +200,7 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH
|
|||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 h1:PyYN9JH5jY9j6av01SpfRMb+1DWg/i3MbGOKPxJ2wjM=
|
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 h1:PyYN9JH5jY9j6av01SpfRMb+1DWg/i3MbGOKPxJ2wjM=
|
||||||
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E=
|
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E=
|
||||||
github.com/swaggo/gin-swagger v1.2.0 h1:YskZXEiv51fjOMTsXrOetAjrMDfFaXD79PEoQBOe2W0=
|
github.com/swaggo/gin-swagger v1.2.0 h1:YskZXEiv51fjOMTsXrOetAjrMDfFaXD79PEoQBOe2W0=
|
||||||
@ -206,6 +208,8 @@ github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05
|
|||||||
github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y=
|
github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y=
|
||||||
github.com/swaggo/swag v1.6.7 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s=
|
github.com/swaggo/swag v1.6.7 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s=
|
||||||
github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc=
|
github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc=
|
||||||
|
github.com/swaggo/swag v1.6.8 h1:z3ZNcpJs/NLMpZcKqXUsBELmmY2Ocy09JXKx5gu3L4M=
|
||||||
|
github.com/swaggo/swag v1.6.8/go.mod h1:a0IpNeMfGidNOcm2TsqODUh9JHdHu3kxDA0UlGbBKjI=
|
||||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||||
github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0=
|
github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0=
|
||||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||||
@ -228,6 +232,7 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
|
|||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
|
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
|
||||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||||
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
@ -255,6 +260,7 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
|
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
|
||||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200923182212-328152dc79b1 h1:Iu68XRPd67wN4aRGGWwwq6bZo/25jR6uu52l/j2KkUE=
|
golang.org/x/net v0.0.0-20200923182212-328152dc79b1 h1:Iu68XRPd67wN4aRGGWwwq6bZo/25jR6uu52l/j2KkUE=
|
||||||
golang.org/x/net v0.0.0-20200923182212-328152dc79b1/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200923182212-328152dc79b1/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
@ -262,6 +268,8 @@ golang.org/x/net v0.0.0-20200927032502-5d4f70055728 h1:5wtQIAulKU5AbLQOkjxl32Uuf
|
|||||||
golang.org/x/net v0.0.0-20200927032502-5d4f70055728/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200927032502-5d4f70055728/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M=
|
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M=
|
||||||
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0 h1:5kGOVHlq0euqwzgTC9Vu15p6fV1Wi0ArVi8da2urnVg=
|
||||||
|
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@ -304,6 +312,7 @@ golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgw
|
|||||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59 h1:QjA/9ArTfVTLfEhClDCG7SGrZkZixxWpwNCDiwJfh88=
|
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59 h1:QjA/9ArTfVTLfEhClDCG7SGrZkZixxWpwNCDiwJfh88=
|
||||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/tools v0.0.0-20200923182640-463111b69878 h1:VUw1+Jf6KJPf82mbTQMia6HCnNMv2BbAipkEZ4KTcqQ=
|
golang.org/x/tools v0.0.0-20200923182640-463111b69878 h1:VUw1+Jf6KJPf82mbTQMia6HCnNMv2BbAipkEZ4KTcqQ=
|
||||||
golang.org/x/tools v0.0.0-20200923182640-463111b69878/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
golang.org/x/tools v0.0.0-20200923182640-463111b69878/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||||
golang.org/x/tools v0.0.0-20200924182824-0f1c53950d78 h1:3JUoxVhcskhsIDEc7vg0MUUEpmPPN5TfG+E97z/Fn90=
|
golang.org/x/tools v0.0.0-20200924182824-0f1c53950d78 h1:3JUoxVhcskhsIDEc7vg0MUUEpmPPN5TfG+E97z/Fn90=
|
||||||
@ -312,6 +321,8 @@ golang.org/x/tools v0.0.0-20200929191002-f1e51e6b9437 h1:XSFqH8m531iIGazX5lrUC9j
|
|||||||
golang.org/x/tools v0.0.0-20200929191002-f1e51e6b9437/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
golang.org/x/tools v0.0.0-20200929191002-f1e51e6b9437/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||||
golang.org/x/tools v0.0.0-20201008184944-d01b322e6f06 h1:w9ail9jFLaySAm61Zjhciu0LQ5i8YTy2pimlNLx4uuk=
|
golang.org/x/tools v0.0.0-20201008184944-d01b322e6f06 h1:w9ail9jFLaySAm61Zjhciu0LQ5i8YTy2pimlNLx4uuk=
|
||||||
golang.org/x/tools v0.0.0-20201008184944-d01b322e6f06/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
golang.org/x/tools v0.0.0-20201008184944-d01b322e6f06/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||||
|
golang.org/x/tools v0.0.0-20201017001424-6003fad69a88 h1:ZB1XYzdDo7c/O48jzjMkvIjnC120Z9/CwgDWhePjQdQ=
|
||||||
|
golang.org/x/tools v0.0.0-20201017001424-6003fad69a88/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@ -353,5 +364,6 @@ gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
|||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
@ -1,15 +1,8 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
import shutil
|
import shutil
|
||||||
import os
|
import os
|
||||||
import argparse
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
"-y", "--yes", help="use assumed node bin directory.", action="store_true"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def runcmd(cmd):
|
def runcmd(cmd):
|
||||||
if os.name == "nt":
|
if os.name == "nt":
|
||||||
@ -19,27 +12,11 @@ def runcmd(cmd):
|
|||||||
|
|
||||||
|
|
||||||
local_path = Path(__file__).resolve().parent
|
local_path = Path(__file__).resolve().parent
|
||||||
out = runcmd("npm bin")
|
|
||||||
|
|
||||||
try:
|
|
||||||
node_bin = Path(out[0].decode("utf-8").rstrip())
|
|
||||||
except:
|
|
||||||
node_bin = Path(out.decode("utf-8").rstrip())
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
if not args.yes:
|
|
||||||
print(f'assuming npm bin directory "{node_bin}". Is this correct?')
|
|
||||||
if input("[yY/nN]: ").lower() == "n":
|
|
||||||
node_bin = local_path.parent / "node_modules" / ".bin"
|
|
||||||
print(f'this? "{node_bin}"')
|
|
||||||
if input("[yY/nN]: ").lower() == "n":
|
|
||||||
node_bin = input("input bin directory: ")
|
|
||||||
|
|
||||||
for mjml in [f for f in local_path.iterdir() if f.is_file() and "mjml" in f.suffix]:
|
for mjml in [f for f in local_path.iterdir() if f.is_file() and "mjml" in f.suffix]:
|
||||||
print(f"Compiling {mjml.name}")
|
print(f"Compiling {mjml.name}")
|
||||||
fname = mjml.with_suffix(".html")
|
fname = mjml.with_suffix(".html")
|
||||||
runcmd(f'{str(node_bin / "mjml")} {str(mjml)} -o {str(fname)}')
|
runcmd(f"npx mjml {str(mjml)} -o {str(fname)}")
|
||||||
if fname.is_file():
|
if fname.is_file():
|
||||||
print("Done.")
|
print("Done.")
|
||||||
|
|
||||||
|
28
main.go
28
main.go
@ -66,6 +66,32 @@ type appContext struct {
|
|||||||
quit chan os.Signal
|
quit chan os.Signal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (app *appContext) loadHTML(router *gin.Engine) {
|
||||||
|
// router.LoadHTMLGlob(filepath.Join(app.local_path, "templates", "*"))
|
||||||
|
// if customHTML := app.config.Section("files").Key("html_templates").MustString(""); customHTML != "" {
|
||||||
|
// app.info.Printf("Loading custom templates from \"%s\"", customHTML)
|
||||||
|
// router.LoadHTMLGlob(filepath.Join(customHTML, "*"))
|
||||||
|
// }
|
||||||
|
customPath := app.config.Section("files").Key("html_templates").MustString("")
|
||||||
|
templatePath := filepath.Join(app.local_path, "templates")
|
||||||
|
htmlFiles, err := ioutil.ReadDir(templatePath)
|
||||||
|
if err != nil {
|
||||||
|
app.err.Fatalf("Couldn't access template directory: \"%s\"", filepath.Join(app.local_path, "templates"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loadFiles := make([]string, len(htmlFiles))
|
||||||
|
for i, f := range htmlFiles {
|
||||||
|
if _, err := os.Stat(filepath.Join(customPath, f.Name())); os.IsNotExist(err) {
|
||||||
|
app.debug.Printf("Using default \"%s\"", f.Name())
|
||||||
|
loadFiles[i] = filepath.Join(templatePath, f.Name())
|
||||||
|
} else {
|
||||||
|
app.info.Printf("Using custom \"%s\"", f.Name())
|
||||||
|
loadFiles[i] = filepath.Join(filepath.Join(customPath, f.Name()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
router.LoadHTMLFiles(loadFiles...)
|
||||||
|
}
|
||||||
|
|
||||||
func GenerateSecret(length int) (string, error) {
|
func GenerateSecret(length int) (string, error) {
|
||||||
bytes := make([]byte, length)
|
bytes := make([]byte, length)
|
||||||
_, err := rand.Read(bytes)
|
_, err := rand.Read(bytes)
|
||||||
@ -465,7 +491,7 @@ func start(asDaemon, firstCall bool) {
|
|||||||
|
|
||||||
router.Use(gin.Recovery())
|
router.Use(gin.Recovery())
|
||||||
router.Use(static.Serve("/", static.LocalFile(filepath.Join(app.local_path, "static"), false)))
|
router.Use(static.Serve("/", static.LocalFile(filepath.Join(app.local_path, "static"), false)))
|
||||||
router.LoadHTMLGlob(filepath.Join(app.local_path, "templates", "*"))
|
app.loadHTML(router)
|
||||||
router.NoRoute(app.NoRouteHandler)
|
router.NoRoute(app.NoRouteHandler)
|
||||||
if debugMode {
|
if debugMode {
|
||||||
app.debug.Println("Loading pprof")
|
app.debug.Println("Loading pprof")
|
||||||
|
@ -3,15 +3,8 @@ import sass
|
|||||||
import subprocess
|
import subprocess
|
||||||
import shutil
|
import shutil
|
||||||
import os
|
import os
|
||||||
import argparse
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
"-y", "--yes", help="use assumed node bin directory.", action="store_true"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def runcmd(cmd):
|
def runcmd(cmd):
|
||||||
if os.name == "nt":
|
if os.name == "nt":
|
||||||
@ -21,32 +14,22 @@ def runcmd(cmd):
|
|||||||
|
|
||||||
|
|
||||||
local_path = Path(__file__).resolve().parent
|
local_path = Path(__file__).resolve().parent
|
||||||
out = runcmd("npm bin")
|
|
||||||
|
|
||||||
try:
|
|
||||||
node_bin = Path(out[0].decode("utf-8").rstrip())
|
|
||||||
except:
|
|
||||||
node_bin = Path(out.decode("utf-8").rstrip())
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
if not args.yes:
|
|
||||||
print(f'assuming npm bin directory "{node_bin}". Is this correct?')
|
|
||||||
if input("[yY/nN]: ").lower() == "n":
|
|
||||||
node_bin = local_path.parent / "node_modules" / ".bin"
|
|
||||||
print(f'this? "{node_bin}"')
|
|
||||||
if input("[yY/nN]: ").lower() == "n":
|
|
||||||
node_bin = input("input bin directory: ")
|
|
||||||
|
|
||||||
for bsv in [d for d in local_path.iterdir() if "bs" in d.name]:
|
for bsv in [d for d in local_path.iterdir() if "bs" in d.name]:
|
||||||
scss = [(bsv / f"{bsv.name}-jf.scss"), (bsv / f"{bsv.name}.scss")]
|
scss = [(bsv / f"{bsv.name}-jf.scss"), (bsv / f"{bsv.name}.scss")]
|
||||||
css = [(bsv / f"{bsv.name}-jf.css"), (bsv / f"{bsv.name}.css")]
|
css = [(bsv / f"{bsv.name}-jf.css"), (bsv / f"{bsv.name}.css")]
|
||||||
min_css = [(bsv.parents[1] / "data" / "static" / f"{bsv.name}-jf.css"), (bsv.parents[1] / "data" / "static" / f"{bsv.name}.css")]
|
min_css = [
|
||||||
|
(bsv.parents[1] / "data" / "static" / f"{bsv.name}-jf.css"),
|
||||||
|
(bsv.parents[1] / "data" / "static" / f"{bsv.name}.css"),
|
||||||
|
]
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
with open(css[i], "w") as f:
|
with open(css[i], "w") as f:
|
||||||
f.write(
|
f.write(
|
||||||
sass.compile(
|
sass.compile(
|
||||||
filename=str(scss[i].resolve()), output_style="expanded", precision=6, omit_source_map_url=True
|
filename=str(scss[i].resolve()),
|
||||||
|
output_style="expanded",
|
||||||
|
precision=6,
|
||||||
|
omit_source_map_url=True,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if css[i].exists():
|
if css[i].exists():
|
||||||
@ -55,29 +38,12 @@ for bsv in [d for d in local_path.iterdir() if "bs" in d.name]:
|
|||||||
cssPath = str(css[i].resolve())
|
cssPath = str(css[i].resolve())
|
||||||
if os.name == "nt":
|
if os.name == "nt":
|
||||||
cssPath = cssPath.replace("\\", "/")
|
cssPath = cssPath.replace("\\", "/")
|
||||||
runcmd(
|
runcmd(f"npx postcss {cssPath} --replace --use autoprefixer")
|
||||||
f'{str((node_bin / "postcss").resolve())} {cssPath} --replace --use autoprefixer'
|
|
||||||
)
|
|
||||||
print(f"{scss[i].name}: Prefixed.")
|
print(f"{scss[i].name}: Prefixed.")
|
||||||
runcmd(
|
runcmd(
|
||||||
f'{str((node_bin / "cleancss").resolve())} --level 1 --format breakWith=lf --output {str(min_css[i].resolve())} {str(css[i].resolve())}'
|
f"npx cleancss --level 1 --format breakWith=lf --output {str(min_css[i].resolve())} {str(css[i].resolve())}"
|
||||||
)
|
)
|
||||||
if min_css[i].exists():
|
if min_css[i].exists():
|
||||||
print(f"{scss[i].name}: Minified and copied to {str(min_css[i].resolve())}.")
|
print(
|
||||||
|
f"{scss[i].name}: Minified and copied to {str(min_css[i].resolve())}."
|
||||||
# for v in [("bootstrap", "bs5"), ("bootstrap4", "bs4")]:
|
)
|
||||||
# new_path = str((local_path.parent / "data" / "static" / (v[1] + ".css")).resolve())
|
|
||||||
# shutil.copy(
|
|
||||||
# str(
|
|
||||||
# (
|
|
||||||
# local_path.parent
|
|
||||||
# / "node_modules"
|
|
||||||
# / v[0]
|
|
||||||
# / "dist"
|
|
||||||
# / "css"
|
|
||||||
# / "bootstrap.min.css"
|
|
||||||
# ).resolve()
|
|
||||||
# ),
|
|
||||||
# new_path,
|
|
||||||
# )
|
|
||||||
# print(f"Copied {v[1]} to {new_path}")
|
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import subprocess
|
|
||||||
import os
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
|
|
||||||
def runcmd(cmd):
|
|
||||||
if os.name == "nt":
|
|
||||||
return subprocess.check_output(cmd, shell=True)
|
|
||||||
proc = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
|
|
||||||
return proc.communicate()
|
|
||||||
|
|
||||||
|
|
||||||
print('Installing npm packages')
|
|
||||||
|
|
||||||
root_path = Path(__file__).parents[1]
|
|
||||||
if os.name == 'nt':
|
|
||||||
root_path /= 'node_modules'
|
|
||||||
|
|
||||||
runcmd('npm install')
|
|
||||||
|
|
||||||
if (root_path / 'node_modules' / 'cleancss').exists() or (root_path / 'cleancss').exists():
|
|
||||||
print(f'Installed successfully in {str((root_path / "node_modules").resolve())}.')
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user