Compare commits
2 Commits
51851910c6
...
95dfe62858
Author | SHA1 | Date |
---|---|---|
Nico Schottelius | 95dfe62858 | |
Nico Schottelius | 05eea37349 |
|
@ -4,7 +4,7 @@
|
||||||
#
|
#
|
||||||
# While trying to install python-ldap
|
# While trying to install python-ldap
|
||||||
|
|
||||||
FROM python:3.10.0-alpine3.15
|
FROM python:3.11.1-alpine3.17
|
||||||
|
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,12 @@
|
||||||
all: requirements
|
IMAGE=ungleich/uncloud
|
||||||
|
|
||||||
|
all: requirements build
|
||||||
|
|
||||||
|
build:
|
||||||
|
sh -c 'docker build -t $(IMAGE):$$(git describe) .'
|
||||||
|
|
||||||
|
pub: build
|
||||||
|
docker push $(IMAGE):$$(git describe)
|
||||||
|
|
||||||
run: requirements
|
run: requirements
|
||||||
. ./env && python manage.py runserver
|
. ./env && python manage.py runserver
|
||||||
|
|
|
@ -12,6 +12,7 @@ machine. Use `kubectl get nodes` to verify minikube is up and running.
|
||||||
* `SECRET_KEY`
|
* `SECRET_KEY`
|
||||||
* `DEBUG`
|
* `DEBUG`
|
||||||
* `DATABASE`
|
* `DATABASE`
|
||||||
|
* Should be: POSTGRES_HOST, POSTGRES_DB, POSTGRES_USER, POSTRES_PASSWORD
|
||||||
|
|
||||||
## Versions
|
## Versions
|
||||||
|
|
||||||
|
@ -35,11 +36,13 @@ machine. Use `kubectl get nodes` to verify minikube is up and running.
|
||||||
* yes: ModelAdmin.formfield_for_manytomany(db_field, request, **kwargs)¶
|
* yes: ModelAdmin.formfield_for_manytomany(db_field, request, **kwargs)¶
|
||||||
* resources should have a slug
|
* resources should have a slug
|
||||||
* can be used as an identifier and non unique names
|
* can be used as an identifier and non unique names
|
||||||
|
* Execute collectstatic for docker
|
||||||
|
|
||||||
#### 3.1 (validation release, planned)
|
#### 3.1 (validation release, planned)
|
||||||
|
|
||||||
* Ensure that one resource cannot have multiple price_per_timeframe of
|
* Ensure that one resource cannot have multiple price_per_timeframe of
|
||||||
the same timeframe
|
the same timeframe
|
||||||
|
* Add wireguard config support
|
||||||
|
|
||||||
|
|
||||||
#### 3.0.2 (planned)
|
#### 3.0.2 (planned)
|
||||||
|
@ -48,13 +51,15 @@ machine. Use `kubectl get nodes` to verify minikube is up and running.
|
||||||
|
|
||||||
#### 3.0.1 (planned)
|
#### 3.0.1 (planned)
|
||||||
|
|
||||||
|
NEXT STEP: CREATE THE ORDER AND RESOURCE ORDER OBJECTS
|
||||||
|
|
||||||
* Show products [done]
|
* Show products [done]
|
||||||
* Link to ProductOrderForm [done]
|
* Link to ProductOrderForm [done]
|
||||||
* Find suitable timeframes for a product [done]
|
* Find suitable timeframes for a product [done]
|
||||||
* Continue to resources / add resources
|
* Continue to resources / add resources
|
||||||
* Need to list resources [done]
|
* Need to list resources [done]
|
||||||
* Need to create manytomany relations for each resource resoluting
|
* Need to create manytomany relations for each resource resoluting
|
||||||
in ResourceOrders1
|
in ResourceOrders
|
||||||
* Need to pass in the price for the selected timeframe [done]
|
* Need to pass in the price for the selected timeframe [done]
|
||||||
* On submit
|
* On submit
|
||||||
* Create ProductOrder
|
* Create ProductOrder
|
||||||
|
|
|
@ -14,15 +14,22 @@ class ProductOneTimeOrderForm(forms.Form):
|
||||||
for res in resources:
|
for res in resources:
|
||||||
print(res)
|
print(res)
|
||||||
field_name = f"{res.slug}"
|
field_name = f"{res.slug}"
|
||||||
if res.minimum_units < res.maximum_units:
|
self.fields[field_name] = forms.FloatField(
|
||||||
self.fields[field_name] = forms.FloatField(
|
required=True,
|
||||||
required=True,
|
label=res.name,
|
||||||
label=res.name,
|
min_value=res.minimum_units,
|
||||||
min_value=res.minimum_units,
|
max_value=res.maximum_units,
|
||||||
max_value=res.maximum_units,
|
widget=NumberInput(attrs={"step": res.step_size}))
|
||||||
widget=NumberInput(attrs={"step": res.step_size}))
|
|
||||||
else:
|
# if res.minimum_units < res.maximum_units:
|
||||||
self.fields[field_name] = forms.FloatField(widget=forms.HiddenInput(attrs={'value': res.minimum_units}))
|
# self.fields[field_name] = forms.FloatField(
|
||||||
|
# required=True,
|
||||||
|
# label=res.name,
|
||||||
|
# min_value=res.minimum_units,
|
||||||
|
# max_value=res.maximum_units,
|
||||||
|
# widget=NumberInput(attrs={"step": res.step_size}))
|
||||||
|
# else:
|
||||||
|
# self.fields[field_name] = forms.FloatField(widget=forms.HiddenInput(attrs={'value': res.minimum_units}))
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
cleaned_data = super().clean()
|
cleaned_data = super().clean()
|
||||||
|
@ -31,7 +38,7 @@ class ProductOneTimeOrderForm(forms.Form):
|
||||||
|
|
||||||
class ProductOrderForm(ProductOneTimeOrderForm):
|
class ProductOrderForm(ProductOneTimeOrderForm):
|
||||||
"""
|
"""
|
||||||
For recurring products (might also have OneTime items
|
For recurring products (might also have OneTime items)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
timeframe = forms.SlugField(required=False, disabled=True)
|
timeframe = forms.SlugField(required=False, disabled=True)
|
||||||
|
|
|
@ -9,12 +9,15 @@ class Command(BaseCommand):
|
||||||
#parser.add_argument('--username', type=str, required=True)
|
#parser.add_argument('--username', type=str, required=True)
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
|
# Add CHF as currency
|
||||||
currency, created = Currency.objects.get_or_create(defaults=
|
currency, created = Currency.objects.get_or_create(defaults=
|
||||||
{
|
{
|
||||||
"slug": "CHF",
|
"slug": "CHF",
|
||||||
"name": "Swiss Franc",
|
"name": "Swiss Franc",
|
||||||
"short_name": "CHF"
|
"short_name": "CHF"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# Add standard timeframes
|
||||||
for timeframe in [ (3600, "1 hour", "1-hour"),
|
for timeframe in [ (3600, "1 hour", "1-hour"),
|
||||||
(86400, "1 day", "1-day"),
|
(86400, "1 day", "1-day"),
|
||||||
(7*86400, "7 days", "7-days"),
|
(7*86400, "7 days", "7-days"),
|
||||||
|
@ -27,9 +30,16 @@ class Command(BaseCommand):
|
||||||
"seconds": timeframe[0]
|
"seconds": timeframe[0]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
tf_30d = TimeFrame.objects.get(slug='30-days')
|
||||||
|
|
||||||
|
# Add typical prices per timeframe
|
||||||
for ppt in [
|
for ppt in [
|
||||||
("1-day", 1, currency),
|
("1-day", 1, currency),
|
||||||
("1-day", 2, currency),
|
("1-day", 2, currency),
|
||||||
|
("30-days", 2, currency), # HDD 100 GB
|
||||||
|
("30-days", 3, currency), # CPU
|
||||||
|
("30-days", 3.5, currency), # SSD Storage
|
||||||
|
("30-days", 4, currency), # RAM
|
||||||
("30-days", 10, currency), # Nextcloud
|
("30-days", 10, currency), # Nextcloud
|
||||||
("30-days", 15, currency), # Gitea
|
("30-days", 15, currency), # Gitea
|
||||||
("30-days", 35, currency), # Matrix
|
("30-days", 35, currency), # Matrix
|
||||||
|
@ -44,32 +54,57 @@ class Command(BaseCommand):
|
||||||
"currency": currency
|
"currency": currency
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# Add typical resources
|
||||||
for res in [
|
for res in [
|
||||||
("cpu-1", "CPU", "Core(s)", None, None),
|
# slug name description min max step-size price per 30days
|
||||||
("cpu-min-max", "CPU", "Core(s)", 1, 20),
|
("cpu-1", "CPU", "Core(s)", None, None, 0.5, 3),
|
||||||
("ram-1", "RAM", "GB", None, None),
|
("cpu-min-max", "CPU", "Core(s)", 1, 20, 0.5, 3),
|
||||||
("ram-min-max", "RAM", "GB", 1, 200),
|
("ram-1", "RAM", "GB", None, None, 0.5, 4),
|
||||||
("matrix-maintenance", "Matrix Maintenance Fee", "", 1, 1),
|
("ram-min-max", "RAM", "GB", 1, 200, 0.5, 4),
|
||||||
("nextcloud-maintenance", "Nextcloud Maintenance Fee", "", 1, 1),
|
("storage-db", "Database-Storage", "GB", 10, None, 10, 3.5),
|
||||||
("gitea-maintenance", "Gitea Maintenance Fee", "", 1, 1),
|
("storage-ssd", "SSD-Storage", "GB", 10, None, 10, 3.5),
|
||||||
|
("storage-hdd", "HDD-Storage", "GB", 100, None, 100, 2),
|
||||||
|
("matrix-maintenance", "Matrix Maintenance Fee", "", 1, 1, None, 35),
|
||||||
|
("nextcloud-maintenance", "Nextcloud Maintenance Fee", "", 1, 1, None, 10),
|
||||||
|
("gitea-maintenance", "Gitea Maintenance Fee", "", 1, 1, None, 15),
|
||||||
|
|
||||||
]:
|
]:
|
||||||
Resource.objects.get_or_create(slug=res[0],
|
this_res, created = Resource.objects.get_or_create(slug=res[0],
|
||||||
defaults=
|
defaults=
|
||||||
{
|
{
|
||||||
"name": res[1],
|
"name": res[1],
|
||||||
"unit": res[2],
|
"unit": res[2],
|
||||||
"minimum_units": res[3],
|
"minimum_units": res[3],
|
||||||
"maximum_units": res[4]
|
"maximum_units": res[4],
|
||||||
|
"step_size": res[5]
|
||||||
})
|
})
|
||||||
|
# If price is given, assign it
|
||||||
|
if res[6]:
|
||||||
|
ppt = PricePerTime.objects.get(timeframe=tf_30d, value=res[6])
|
||||||
|
this_res.price_per_time.add(ppt)
|
||||||
|
|
||||||
|
|
||||||
|
# Link resources to prices per time frame
|
||||||
|
|
||||||
# Link to PPT -- later
|
# Link to PPT -- later
|
||||||
# for ppt_res in res[5]:
|
# for ppt_res in res[5]:
|
||||||
# ppt = PricePerTime.objects.get(
|
# ppt = PricePerTime.objects.get(
|
||||||
|
|
||||||
|
# Add test products
|
||||||
for product in [
|
for product in [
|
||||||
("matrix", "Matrix"),
|
("matrix", "Matrix"),
|
||||||
("nextcloud", "Nextcloud"),
|
("nextcloud", "Nextcloud"),
|
||||||
("gitea", "Gitea") ]:
|
("gitea", "Gitea") ]:
|
||||||
Product.objects.get_or_create(slug=product[0],
|
p, created = Product.objects.get_or_create(slug=product[0],
|
||||||
defaults = { "name": product[1] })
|
defaults = { "name": product[1] })
|
||||||
|
|
||||||
|
for req_res in [ "cpu-min-max",
|
||||||
|
"ram-min-max",
|
||||||
|
"storage-db",
|
||||||
|
"storage-hdd" ]:
|
||||||
|
print(f"Adding {req_res} to {p}")
|
||||||
|
p.resources.add(Resource.objects.get(slug=req_res))
|
||||||
|
|
||||||
|
p.resources.add(Resource.objects.get(slug=f"{product[0]}-maintenance"))
|
||||||
|
# Every test product can be bought for the 30d timeframe
|
||||||
|
p.timeframes.add(tf_30d)
|
||||||
|
|
|
@ -64,8 +64,9 @@ class Resource(models.Model):
|
||||||
step_size = models.FloatField(default=1) # step size
|
step_size = models.FloatField(default=1) # step size
|
||||||
|
|
||||||
price_per_time = models.ManyToManyField(PricePerTime, blank=True)
|
price_per_time = models.ManyToManyField(PricePerTime, blank=True)
|
||||||
#onetime_price = models.ManyToManyField(OneTimePrice, blank=True)
|
onetime_price = models.ForeignKey(OneTimePrice,
|
||||||
onetime_price = models.ForeignKey(OneTimePrice, null=True, on_delete=models.CASCADE)
|
null=True, blank=True,
|
||||||
|
on_delete=models.CASCADE)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if self.minimum_units:
|
if self.minimum_units:
|
||||||
|
|
|
@ -8,5 +8,5 @@ you to manage all your resources.
|
||||||
<h2>What can I do with uncloud?</h2>
|
<h2>What can I do with uncloud?</h2>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>You can<a href="{% url 'products' %}">order products</a></li>
|
<li>You can <a href="{% url 'products' %}">order products</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -9,5 +9,5 @@
|
||||||
<table>
|
<table>
|
||||||
{{ form }}
|
{{ form }}
|
||||||
</table>
|
</table>
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
<button type="submit" class="btn btn-primary">Order</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -97,6 +97,10 @@ class ProductSelectView(CreateView):
|
||||||
fields = ['product' ]
|
fields = ['product' ]
|
||||||
|
|
||||||
class IndexView(TemplateView):
|
class IndexView(TemplateView):
|
||||||
|
"""
|
||||||
|
The starting page containing a short intro
|
||||||
|
"""
|
||||||
|
|
||||||
template_name = "app/index.html"
|
template_name = "app/index.html"
|
||||||
|
|
||||||
class Yearly(TemplateView):
|
class Yearly(TemplateView):
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
name=uncloud:$(git describe)
|
name=ungleich/uncloud:$(git describe)
|
||||||
docker build -t ${name} .
|
docker build -t ${name} .
|
||||||
|
|
||||||
# check for args
|
# check for args
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Django basics
|
# Django basics
|
||||||
Django==4.0
|
Django==4.0.5
|
||||||
djangorestframework
|
djangorestframework
|
||||||
django-auth-ldap
|
django-auth-ldap
|
||||||
|
|
Loading…
Reference in New Issue