Compare commits

...

2 Commits

Author SHA1 Message Date
Nico Schottelius 95dfe62858 upgrade to python 3.11.1 2023-02-05 21:13:30 +01:00
Nico Schottelius 05eea37349 Cleanup and more demo products 2022-07-16 18:22:52 +02:00
11 changed files with 90 additions and 30 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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:

View File

@ -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>

View File

@ -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>

View File

@ -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):

View File

@ -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

View File

@ -1,4 +1,4 @@
# Django basics # Django basics
Django==4.0 Django==4.0.5
djangorestframework djangorestframework
django-auth-ldap django-auth-ldap