Merge pull request 'feat: notify user on instance creation' (#14) from wip-instance-ready-notify into master

Reviewed-on: https://gitea.hostea.org/Hostea/dashboard/pulls/14
wip-site
Aravinth Manivannan 2022-07-02 03:42:34 -04:00
commit ccfa81ce2c
23 changed files with 321 additions and 118 deletions

View File

@ -4,7 +4,7 @@ pipeline:
environment:
- DATABSE_URL=postgres://postgres:password@database:5432/postgres
- EMAIL_URL=smtp://admin:password@smtp:10025
- HOSTEA_INFRA_HOSTEA_REPO_REMOTE=ssh://git@gitea:22/hostea/fleet.git
- HOSTEA_INFRA_HOSTEA_REPO_REMOTE=ssh://git@gitea:22/hostea/
- HOSTEA_META_GITEA_INSTANCE=http://gitea:3000
commands:
- export HOSTEA_INFRA_HOSTEA_REPO_SSH_KEY="$(realpath ./tests/fleet-deploy-key)"

View File

@ -2,20 +2,6 @@
<div class="footer__container">
<div class="footer__column">
<span class="license__conatiner">
<a class="license__link" rel="noreferrer" href="/docs" target="_blank"
>Docs</a
>
<span class="footer__column-divider--mobile-visible">|</span>
<a
class="license__link"
rel="noreferrer"
href="https://www.eff.org/issues/do-not-track/amp/"
target="_blank"
>No AMP</a
>
</span>
</div>
<div class="footer__column">
<a
href="/"
class="footer__link"
@ -23,6 +9,21 @@
rel="noopener"
title="RSS"
>Home</a>
<span class="footer__column-divider--mobile-visible">|</span>
<a class="license__link" rel="noreferrer" href="https://hostea.org/about" target="_blank"
>&nbsp; About</a
>
</span>
</div>
<div class="footer__column">
<a
class="license__link"
rel="noreferrer"
href="https://www.eff.org/issues/do-not-track/amp/"
target="_blank"
>No AMP</a
>
<div class="footer__column-divider">|</div>
<a href="mailto:{{ footer.admin_email }}" class="footer__link"
>Contact Instance Maintainer</a
@ -30,12 +31,12 @@
<div class="footer__column-divider">|</div>
<a
class="footer__link"
href="{{ footer.source_code }}"
href="{{ footer.source_code.link }}"
target="_blank"
rel="noopener"
title="Source Code"
>
v{{ footer.version }}-{{ footer.git_hash }}
{{ footer.source_code.text }}
</a>
</div>
</div>

View File

@ -23,6 +23,7 @@ from django.http import HttpResponse
from django.views.decorators.csrf import csrf_protect
from django.urls import reverse
from dash.utils import footer_ctx
from .models import AccountConfirmChallenge
from .utils import send_verification_email, ConfirmAccess
@ -35,6 +36,7 @@ def login_view(request):
def default_login_ctx():
return {
"title": "Login",
"footer": footer_ctx(),
}
if request.method == "GET":
@ -102,6 +104,7 @@ def register_view(request):
"title": "Register",
"username": username,
"email": username,
"footer": footer_ctx(),
}
if request.method == "GET":
@ -213,6 +216,7 @@ def sudo(request):
def default_login_ctx():
return {
"title": "Confirm Access",
"footer": footer_ctx(),
}
if request.method == "GET":

View File

@ -26,7 +26,7 @@ from django.conf import settings
from payments import get_payment_model, RedirectNeeded, PaymentStatus
from accounts.tests import register_util, login_util
from dash.tests import create_configurations, create_instance_util
from dash.tests import create_configurations, create_instance_util, infra_custom_config
from dash.models import Instance
from .models import Payment
@ -43,55 +43,21 @@ class BillingTest(TestCase):
register_util(t=self, username=self.username)
create_configurations(t=self)
@override_settings(HOSTEA=infra_custom_config(test_name="test_payments"))
def test_payments(self):
c = Client()
login_util(self, c, "accounts.home")
instance_name = "test_create_instance_renders"
instance_name = "test_payments"
create_instance_util(
t=self, c=c, instance_name=instance_name, config=self.instance_config[0]
)
instance = Instance.objects.get(name=instance_name)
payment_uri = reverse("billing.invoice.generate", args=(instance_name,))
# generate invoice
resp = c.get(payment_uri)
self.assertEqual(resp.status_code, 302)
invoice_uri = resp.headers["Location"]
self.assertEqual("invoice/payment/" in invoice_uri, True)
# try to generate duplicate invoice, but should get redirected to previous invoice
resp = c.get(payment_uri)
self.assertEqual(resp.status_code, 302)
self.assertEqual(invoice_uri == resp.headers["Location"], True)
# check if invoice details page is displaying the invoice
# if payment is yet to be made:
# template will show payment button
# else:
# template will show payment date
resp = c.get(invoice_uri)
self.assertEqual(str.encode(instance_name) in resp.content, True)
self.assertEqual(
str.encode(str(self.instance_config[0].rent)) in resp.content, True
)
self.assertEqual(str.encode("Paid on") in resp.content, False)
# check if the unpaid invoice is displayed in the pending invoice view
resp = c.get(reverse("billing.invoice.pending"))
self.assertEqual(str.encode(invoice_uri) in resp.content, True)
self.assertEqual(payment_fullfilled(instance=instance), False)
# simulate payment. There's probably a better way to do this
payment = get_payment_model().objects.get(paid_by=self.user)
payment.status = PaymentStatus.CONFIRMED
payment.save()
self.assertEqual(payment_fullfilled(instance=instance), True)
#
payment = get_payment_model().objects.get(paid_by=self.user)
invoice_uri = reverse("billing.invoice.details", args=(payment.public_ref,))
# check if paid invoice is listed in paid invoice list view
resp = c.get(reverse("billing.invoice.paid"))
@ -111,6 +77,7 @@ class BillingTest(TestCase):
# try to generate an invoice for the second time on the same VM
# shouldn't be possible since payment is already made for the duration
payment_uri = reverse("billing.invoice.generate", args=(instance.name,))
resp = c.get(payment_uri)
self.assertEqual(resp.status_code, 400)

View File

@ -24,6 +24,7 @@ from payments import get_payment_model, RedirectNeeded, PaymentStatus
from dash.models import Instance
from django.db.models import Q
from infrastructure.utils import create_vm_if_not_exists
from dash.utils import footer_ctx
def default_ctx(title: str, username: str):
@ -33,6 +34,7 @@ def default_ctx(title: str, username: str):
return {
"title": title,
"username": username,
"footer": footer_ctx(),
}

View File

@ -12,6 +12,7 @@
</ul>
<p>Created On: {{ instance.created_at }}</p>
<p><a href="{{gitea_uri}}">Gitea Instance</a>|<a href="{{woodpecker}}">Woodpecker CI</a></p>
<form
action="{% url 'dash.instances.delete' name=instance.name %}"

View File

@ -12,12 +12,20 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import subprocess
import shutil
import os
from time import sleep
from pathlib import Path
from django.contrib.auth import get_user_model
from django.utils.http import urlencode
from django.urls import reverse
from django.test import TestCase, Client, override_settings
from django.conf import settings
from django.db.utils import IntegrityError
from payments import get_payment_model, RedirectNeeded, PaymentStatus
from accounts.tests import login_util, register_util
@ -44,6 +52,28 @@ def create_configurations(t: TestCase):
)
def infra_custom_config(test_name: str):
def create_fleet_repo(test_name: str):
subprocess.run(
["./integration/ci.sh", "new_fleet_repo", test_name],
stdout=subprocess.DEVNULL,
stderr=subprocess.STDOUT,
)
sleep(10)
create_fleet_repo(test_name=test_name)
c = settings.HOSTEA
path = Path(f"/tmp/hostea/dashboard/{test_name}/repo")
if path.exists():
shutil.rmtree(path)
c["INFRA"]["HOSTEA_REPO"]["PATH"] = str(path)
remote_base = os.environ.get("HOSTEA_INFRA_HOSTEA_REPO_REMOTE")
c["INFRA"]["HOSTEA_REPO"]["REMOTE"] = f"{remote_base}{test_name}.git"
print(c["INFRA"]["HOSTEA_REPO"]["REMOTE"])
return c
def create_instance_util(
t: TestCase, c: Client, instance_name: str, config: InstanceConfiguration
):
@ -55,6 +85,22 @@ def create_instance_util(
resp.headers["location"],
reverse("billing.invoice.generate", args=(instance_name,)),
)
# generate invoice
payment_uri = reverse("billing.invoice.generate", args=(instance_name,))
resp = c.get(payment_uri)
t.assertEqual(resp.status_code, 302)
invoice_uri = resp.headers["Location"]
t.assertEqual("invoice/payment/" in invoice_uri, True)
# simulate payment. There's probably a better way to do this
payment = get_payment_model().objects.get(
paid_by=t.user, instance_name=instance_name
)
payment.status = PaymentStatus.CONFIRMED
payment.save()
resp = c.get(reverse("infra.create", args=(instance_name,)))
t.assertEqual(resp.status_code, 200)
class DashHome(TestCase):
@ -151,6 +197,9 @@ class CreateInstance(TestCase):
register_util(t=self, username="createinstance_user")
create_configurations(t=self)
@override_settings(
HOSTEA=infra_custom_config(test_name="test_create_instance_renders")
)
def test_create_instance_renders(self):
c = Client()
login_util(self, c, "accounts.home")
@ -236,12 +285,16 @@ class CreateInstance(TestCase):
resp = c.post(delete_uri)
self.assertEqual(resp.status_code, 302)
self.assertEqual(resp.headers["location"], reverse("dash.home"))
self.assertEqual(
resp.headers["location"], reverse("infra.rm", args=(instance.name,))
)
resp = c.get(resp.headers["location"])
self.assertEqual(resp.status_code, 302)
self.assertEqual(resp.headers["location"], reverse("dash.instances.list"))
self.assertEqual(
Instance.objects.filter(
name=instance.name,
name=instance_name,
owned_by=self.user,
configuration_id=self.instance_config[0],
).exists(),
False,
)

View File

@ -14,7 +14,9 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from enum import Enum, unique
from git import Repo
from django.contrib.auth.models import User
from django.conf import settings
from .models import Instance, InstanceConfiguration
@ -55,3 +57,30 @@ def create_instance(vm_name: str, configuration_name: str, user: User) -> Instan
instance = Instance(name=vm_name, configuration_id=configuration, owned_by=user)
instance.save()
return instance
source_code = None
def footer_ctx():
global source_code
if source_code is None:
if "SOURCE_CODE" in settings.HOSTEA:
source_code = {
"text": "Source Code",
"link": settings.HOSTEA["SOURCE_CODE"],
}
else:
link = "https://gitea.hostea.org/Hostea/dashboard"
source_code = {"text": "Source Code", "link": link}
try:
r = Repo(".")
commit = r.head.commit.hexsha
source_code["text"] = f"v-{commit.hexsha[0:8]}"
except:
pass
return {
"source_code": source_code,
"admin_email": settings.HOSTEA["INSTANCE_MAINTAINER_CONTACT"],
}

View File

@ -22,9 +22,15 @@ from django.views.decorators.csrf import csrf_protect
from django.urls import reverse
from accounts.decorators import confirm_access
from infrastructure.utils import Infra
from .models import Instance, InstanceConfiguration
from .utils import create_instance as create_instance_util, VmErrors, VmException
from .utils import (
create_instance as create_instance_util,
VmErrors,
VmException,
footer_ctx,
)
def default_ctx(title: str, username: str):
@ -35,6 +41,7 @@ def default_ctx(title: str, username: str):
"title": title,
"username": username,
"open_instances": "open",
"footer": footer_ctx(),
}
@ -113,7 +120,12 @@ def view_instance(request, name: str):
instance = get_object_or_404(Instance, owned_by=user, name=name)
ctx = default_ctx(title=PAGE_TITLE, username=user.username)
instance.configuration = instance.configuration_id
gitea_uri = Infra.get_gitea_uri(instance=instance)
woodpecker = Infra.get_woodpecker_uri(instance=instance)
ctx["instance"] = instance
ctx["woodpecker"] = woodpecker
ctx["gitea_uri"] = gitea_uri
return render(request, "dash/instances/view/index.html", context=ctx)
@ -130,5 +142,4 @@ def delete_instance(request, name):
ctx["instance"] = instance
return render(request, "dash/instances/delete/index.html", context=ctx)
instance.delete()
return redirect(reverse("dash.home"))
return redirect(reverse("infra.rm", args=(instance.name,)))

View File

@ -54,6 +54,7 @@ PAYMENT_VARIANTS = {
### Dashbaord specific configuration options
HOSTEA = {
"SOURCE_CODE": "https://gitea.hostea.org/Hostea/dashboard",
"INSTANCE_MAINTAINER_CONTACT": "contact@hostea.example.org",
"ACCOUNTS": {
"MAX_VERIFICATION_TOLERANCE_PERIOD": 60 * 60 * 24, # in seconds

View File

@ -53,6 +53,7 @@ PAYMENT_VARIANTS = {
### Dashbaord specific configuration options
HOSTEA = {
"SOURCE_CODE": "https://gitea.hostea.org/Hostea/dashboard",
"INSTANCE_MAINTAINER_CONTACT": "contact@hostea.example.org",
"ACCOUNTS": {
"MAX_VERIFICATION_TOLERANCE_PERIOD": 60 * 60 * 24, # in seconds

View File

@ -168,6 +168,7 @@ PAYMENT_VARIANTS = {
### Dashbaord specific configuration options
HOSTEA = {
"SOURCE_CODE": "https://gitea.hostea.org/Hostea/dashboard",
"RESTRICT_NEW_INTEGRATION_INSTALLATION": True,
"INSTANCE_MAINTAINER_CONTACT": "contact@hostea.example.org",
"ACCOUNTS": {

View File

@ -119,7 +119,7 @@ class Command(BaseCommand):
vm_name = options[self.vm_name_key]
if Instance.objects.filter(name=vm_name).exists():
instance = Instance.objects.get(name=vm_name)
delete_vm(instance=instance, owner=instance.owned_by.username)
delete_vm(instance=instance)
def handle(self, *args, **options):
for i in [self.action_key, self.vm_name_key]:

View File

@ -0,0 +1,36 @@
# Generated by Django 4.0.3 on 2022-06-29 18:30
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("dash", "0006_auto_20220619_0800"),
("infrastructure", "0005_remove_instancecreated_gitea_password"),
]
operations = [
migrations.CreateModel(
name="Job",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("job_type", models.CharField(max_length=10, verbose_name="Job Type")),
(
"instance",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="dash.instance"
),
),
],
),
]

View File

@ -12,11 +12,30 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from django.db import models
from enum import Enum, unique
from django.db import models
from dash.models import Instance
@unique
class JobType(Enum):
PING = "ping"
def __str__(self):
return self.name
class InstanceCreated(models.Model):
instance = models.ForeignKey(Instance, on_delete=models.PROTECT)
created = models.BooleanField(default=False)
class Job(models.Model):
instance = models.ForeignKey(Instance, on_delete=models.CASCADE)
job_type = models.CharField(
"Job Type",
max_length=10,
null=False,
)

View File

@ -14,12 +14,11 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import shutil
import time
import os
import requests
from io import StringIO
from urllib.parse import urlparse, urlunparse
from urllib.parse import urlunparse
from pathlib import Path
import requests
from django.test import TestCase, Client, override_settings
from django.conf import settings
from django.core.management import call_command
@ -28,20 +27,11 @@ from git import Repo
from dash.models import Instance, InstanceConfiguration
from accounts.tests import register_util, login_util
from dash.tests import create_configurations, create_instance_util
from dash.tests import create_configurations, create_instance_util, infra_custom_config
from infrastructure.management.commands.vm import translate_sizes
from .utils import Infra
from .models import InstanceCreated
def custom_config(test_name: str):
c = settings.HOSTEA
path = Path(f"/tmp/hostea/dashboard/{test_name}/repo")
if path.exists():
shutil.rmtree(path)
c["INFRA"]["HOSTEA_REPO"]["PATH"] = str(path)
return c
from .utils import Infra, Worker
from .models import InstanceCreated, Job, JobType
class InfraUtilTest(TestCase):
@ -54,7 +44,7 @@ class InfraUtilTest(TestCase):
register_util(t=self, username=self.username)
create_configurations(t=self)
@override_settings(HOSTEA=custom_config(test_name="test_path_util"))
@override_settings(HOSTEA=infra_custom_config(test_name="test_path_util"))
def test_path_utils(self):
infra = Infra()
subdomain = "foo"
@ -85,7 +75,7 @@ class InfraUtilTest(TestCase):
infra._hostscript_path(subdomain=subdomain),
)
@override_settings(HOSTEA=custom_config(test_name="test_add_vm"))
@override_settings(HOSTEA=infra_custom_config(test_name="test_add_vm"))
def test_add_vm(self):
infra = Infra()
c = Client()
@ -105,9 +95,12 @@ class InfraUtilTest(TestCase):
after_add = infra.repo.head.commit.hexsha
self.assertEqual(before_add is not after_add, True)
c = custom_config(test_name="test_add_vm--get-head")
path = c["INFRA"]["HOSTEA_REPO"]["PATH"]
# c = infra_custom_config(test_name="test_add_vm--get-head")
path = Path("/tmp/hostea/dashboard/check-test_add_vm")
if path.exists():
shutil.rmtree(path)
repo = Repo.clone_from(conf["REMOTE"], path, env=infra.env)
repo.git.pull(env=infra.env)
self.assertEqual(repo.head.commit.hexsha == after_add, True)
before_rm = infra.repo.head.commit.hexsha
@ -115,10 +108,10 @@ class InfraUtilTest(TestCase):
after_rm = infra.repo.head.commit.hexsha
self.assertEqual(before_add is not after_add, True)
repo.git.pull()
repo.git.pull(env=infra.env)
self.assertEqual(repo.head.commit.hexsha == after_rm, True)
@override_settings(HOSTEA=custom_config(test_name="test_cmd"))
@override_settings(HOSTEA=infra_custom_config(test_name="test_cmd"))
def test_cmd(self):
subdomain = "cmd_vm"
infra = Infra()
@ -187,3 +180,26 @@ class InfraUtilTest(TestCase):
# run delete VM command to crudely check idempotency
call_command("vm", "delete", subdomain)
def test_worker(self):
subdomain = "gitea" # yes, gitea.hostea.org exists. will use it till I
# figure out how to use requests_mock within django
c = Client()
login_util(self, c, "accounts.home")
create_instance_util(
t=self, c=c, instance_name=subdomain, config=self.instance_config[0]
)
instance = Instance.objects.get(name=subdomain)
job = Job.objects.create(instance=instance, job_type=JobType.PING)
gitea_uri = Infra.get_gitea_uri(instance=instance)
print(f"mocking {gitea_uri}")
w = Worker(job=job)
w.start()
time.sleep(15)
self.assertEqual(w.is_alive(), False)
w.join()
self.assertEqual(
Job.objects.filter(instance=instance, job_type=JobType.PING).exists(), True
)

View File

@ -15,17 +15,60 @@
import os
import shutil
import yaml
import requests
from pathlib import Path
from threading import Thread, Event
from time import sleep
from django.utils.crypto import get_random_string
from django.template.loader import render_to_string
from django.core.mail import send_mail
from django.conf import settings
from git import Repo, Commit
from git.exc import InvalidGitRepositoryError
from dash.models import Instance
from .models import InstanceCreated
from infrastructure.models import InstanceCreated, JobType, Job
class Worker(Thread):
def __init__(self, job: Job):
self.job = job
super().__init__()
def run(self):
gitea_uri = Infra.get_gitea_uri(instance=self.job.instance)
woodpecker = Infra.get_woodpecker_uri(instance=self.job.instance)
while True:
try:
print(f"[ping] Trying to reach {gitea_uri}")
resp = requests.get(gitea_uri)
if resp.status_code == 200:
break
except Exception:
return False
sleep(10)
job = self.job
self.job = None
email = job.instance.owned_by.email
send_mail(
subject="[Hostea] Your Hostea instance is now online!",
message=f"""
Hello,
The deployment job has run to completion and your Hostea instance is now online!
Credentials to admin account was sent in an earlier email, please contact
support if didn't receive it.
Gitea: {gitea_uri}
Woodpecker CI: {woodpecker}
""",
from_email="No reply Hostea<no-reply@exampl.org>", # TODO read from settings.py
recipient_list=[email],
)
job.delete()
def create_vm_if_not_exists(instance: Instance) -> (str, Commit):
@ -35,18 +78,20 @@ def create_vm_if_not_exists(instance: Instance) -> (str, Commit):
infra = Infra()
if not InstanceCreated.objects.filter(instance=instance).exists():
(gitea_password, commit) = infra.add_vm(instance=instance)
instance = InstanceCreated.objects.create(instance=instance, created=True)
instance.save()
InstanceCreated.objects.create(instance=instance, created=True)
job = Job.objects.create(instance=instance, job_type=str(JobType.PING))
Worker(job=job).start()
return (gitea_password, commit)
else:
if str.strip(infra.get_flavor(instance=instance)) != str.strip(
infra.translate_size(instance=instance)
):
# Worker.init_global()
return infra.add_vm(instance=instance)
return None
def delete_vm(instance: Instance, owner: str):
def delete_vm(instance: Instance):
infra = Infra()
infra.remove_vm(instance=instance)
if InstanceCreated.objects.filter(instance=instance).exists():
@ -97,10 +142,10 @@ class Infra:
"""
Get Woodpecker hostname of an instance
"""
return (f"{instance.name}-ci",)
return f"{instance.name}-ci"
@classmethod
def get_woodpecker_hostname(cls, instance: Instance) -> str:
def get_woodpecker_uri(cls, instance: Instance) -> str:
"""
Get an instance's Gitea URI
"""
@ -179,7 +224,9 @@ class Infra:
)
def _pull(self):
self.repo.git.pull(env=self.env, rebase="true")
self.repo.git.fetch(env=self.env)
# TODO: switch to using Git cmd
@staticmethod
def translate_size(instance: Instance) -> str:

View File

@ -26,7 +26,7 @@ from accounts.decorators import confirm_access
from dash.models import Instance
from billing.utils import payment_fullfilled
from .utils import create_vm_if_not_exists, Infra
from .utils import create_vm_if_not_exists, Infra, delete_vm
def default_ctx(title: str, username: str):
@ -62,7 +62,7 @@ your new Gitea instance. Great powers come with great responsibilities,
so use the admin credentials wisely. When in doubt, consult the Gitea
docs or contact support!\n
-username : root
- username : root
- password: {gitea_password}
""",
from_email="No reply Hostea<no-reply@exampl.org>", # TODO read from settings.py
@ -84,7 +84,5 @@ def delete_instance(request, instance_name: str):
Dashboard homepage view
"""
instance = get_object_or_404(Instance, name=instance_name, owned_by=request.user)
infra = Infra()
infra.remove_vm(instance=instance)
# TODO: push isn't implemented yet
return HttpResponse()
delete_vm(instance=instance)
return redirect(reverse("dash.instances.list"))

View File

@ -11,6 +11,7 @@ init() {
else
docker_compose_down || true
docker_compose_up
sed -i /localhost.*/d ~/.ssh/known_hosts
setup_env
sleep 5
# wait_for_env
@ -29,4 +30,8 @@ teardown() {
fi
}
$1
new_fleet_repo() {
new_fleet_repo_init $2
}
$1 $@

View File

@ -120,31 +120,20 @@ support_repo_init() {
$GITEA_HOSTEA_SUPPORT_REPO
}
# register user "Hostea" on Gitea and create support repository
fleet_repo_init() {
python -m integration \
gitea register \
$GITEA_HOSTEA_USERNAME $GITEA_HOSTEA_PASSWORD \
$GITEA_HOSTEA_EMAIL \
$GITEA_URL || true
python -m integration \
gitea login \
$GITEA_HOSTEA_USERNAME $GITEA_HOSTEA_PASSWORD \
$GITEA_HOSTEA_EMAIL \
$GITEA_URL
new_fleet_repo_init() {
python -m integration \
gitea create_repo \
$GITEA_HOSTEA_USERNAME $GITEA_HOSTEA_PASSWORD \
$GITEA_HOSTEA_EMAIL \
$GITEA_URL \
$GITEA_HOSTEA_FLEET_REPO
$1
python -m integration \
gitea add_deploy_key \
$GITEA_HOSTEA_USERNAME $GITEA_HOSTEA_PASSWORD \
$GITEA_HOSTEA_EMAIL \
$GITEA_URL \
$GITEA_HOSTEA_FLEET_REPO \
$1 \
$GITEA_HOSTEA_FLEET_DEPLOY_KEY
tmp_dir=$(mktemp -d)
@ -159,7 +148,8 @@ fleet_repo_init() {
git init
git add README
git commit -m "init"
git remote add origin $GITEA_HOSTEA_FLEET_REPO_REMOTE
REMOTE="$GITEA_SSH_URL/$GITEA_HOSTEA_USERNAME/$1.git"
git remote add origin $REMOTE
GIT_SSH_COMMAND="/usr/bin/ssh -oStrictHostKeyChecking=no -i $GITEA_HOSTEA_FLEET_DEPLOY_KEY_PRIVATE" \
git push --set-upstream origin master
popd
@ -167,6 +157,24 @@ fleet_repo_init() {
}
# register user "Hostea" on Gitea and create support repository
fleet_repo_init() {
python -m integration \
gitea register \
$GITEA_HOSTEA_USERNAME $GITEA_HOSTEA_PASSWORD \
$GITEA_HOSTEA_EMAIL \
$GITEA_URL || true
python -m integration \
gitea login \
$GITEA_HOSTEA_USERNAME $GITEA_HOSTEA_PASSWORD \
$GITEA_HOSTEA_EMAIL \
$GITEA_URL
new_fleet_repo_init $GITEA_HOSTEA_FLEET_REPO
}
# Create user on Hostea to simulate a Hostea customer
hostea_customer_simulation() {
python -m integration \

View File

@ -37,6 +37,7 @@ pynvim==0.4.3
pytz==2022.1
PyYAML==6.0
requests==2.27.1
six==1.16.0
smmap==5.0.0
sqlparse==0.4.2
stripe==3.4.0

View File

@ -34,11 +34,9 @@ h2 {
body {
width: 100%;
min-height: 100vh;
/*
display: flex;
flex-direction: column;
justify-content: space-between;
*/
}
a:hover {
@ -244,6 +242,8 @@ footer {
display: block;
font-size: 0.7rem;
margin-bottom: 5px;
margin-left: 260px;
width: 100%;
}
.footer__container {
@ -391,6 +391,8 @@ footer {
font-size: 0.7rem;
padding: 0;
margin: 0;
margin-left: 260px;
width: calc(100vw - 260px);
}
.footer__container {
@ -607,8 +609,6 @@ fieldset {
background-color: #e11d21;
}
/*
.form__label {
margin: 5px 0;

View File

@ -15,6 +15,7 @@
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from dash.utils import footer_ctx
from .utils import IssueTracker
@ -28,6 +29,7 @@ def default_ctx(title: str, username: str):
"username": username,
"open_support": "open",
"support": {"list": it.get_issue_tracker(), "new": it.open_issue()},
"footer": footer_ctx(),
}