Cleanup and more demo products
This commit is contained in:
parent
51851910c6
commit
05eea37349
|
@ -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
|
||||
. ./env && python manage.py runserver
|
||||
|
|
|
@ -12,6 +12,7 @@ machine. Use `kubectl get nodes` to verify minikube is up and running.
|
|||
* `SECRET_KEY`
|
||||
* `DEBUG`
|
||||
* `DATABASE`
|
||||
* Should be: POSTGRES_HOST, POSTGRES_DB, POSTGRES_USER, POSTRES_PASSWORD
|
||||
|
||||
## 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)¶
|
||||
* resources should have a slug
|
||||
* can be used as an identifier and non unique names
|
||||
* Execute collectstatic for docker
|
||||
|
||||
#### 3.1 (validation release, planned)
|
||||
|
||||
* Ensure that one resource cannot have multiple price_per_timeframe of
|
||||
the same timeframe
|
||||
* Add wireguard config support
|
||||
|
||||
|
||||
#### 3.0.2 (planned)
|
||||
|
@ -48,13 +51,15 @@ machine. Use `kubectl get nodes` to verify minikube is up and running.
|
|||
|
||||
#### 3.0.1 (planned)
|
||||
|
||||
NEXT STEP: CREATE THE ORDER AND RESOURCE ORDER OBJECTS
|
||||
|
||||
* Show products [done]
|
||||
* Link to ProductOrderForm [done]
|
||||
* Find suitable timeframes for a product [done]
|
||||
* Continue to resources / add resources
|
||||
* Need to list resources [done]
|
||||
* Need to create manytomany relations for each resource resoluting
|
||||
in ResourceOrders1
|
||||
in ResourceOrders
|
||||
* Need to pass in the price for the selected timeframe [done]
|
||||
* On submit
|
||||
* Create ProductOrder
|
||||
|
|
|
@ -14,15 +14,22 @@ class ProductOneTimeOrderForm(forms.Form):
|
|||
for res in resources:
|
||||
print(res)
|
||||
field_name = f"{res.slug}"
|
||||
if res.minimum_units < res.maximum_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}))
|
||||
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}))
|
||||
|
||||
# if res.minimum_units < res.maximum_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):
|
||||
cleaned_data = super().clean()
|
||||
|
@ -31,7 +38,7 @@ class ProductOneTimeOrderForm(forms.Form):
|
|||
|
||||
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)
|
||||
|
|
|
@ -9,12 +9,15 @@ class Command(BaseCommand):
|
|||
#parser.add_argument('--username', type=str, required=True)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# Add CHF as currency
|
||||
currency, created = Currency.objects.get_or_create(defaults=
|
||||
{
|
||||
"slug": "CHF",
|
||||
"name": "Swiss Franc",
|
||||
"short_name": "CHF"
|
||||
})
|
||||
|
||||
# Add standard timeframes
|
||||
for timeframe in [ (3600, "1 hour", "1-hour"),
|
||||
(86400, "1 day", "1-day"),
|
||||
(7*86400, "7 days", "7-days"),
|
||||
|
@ -27,9 +30,16 @@ class Command(BaseCommand):
|
|||
"seconds": timeframe[0]
|
||||
})
|
||||
|
||||
tf_30d = TimeFrame.objects.get(slug='30-days')
|
||||
|
||||
# Add typical prices per timeframe
|
||||
for ppt in [
|
||||
("1-day", 1, 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", 15, currency), # Gitea
|
||||
("30-days", 35, currency), # Matrix
|
||||
|
@ -44,32 +54,57 @@ class Command(BaseCommand):
|
|||
"currency": currency
|
||||
})
|
||||
|
||||
# Add typical resources
|
||||
for res in [
|
||||
("cpu-1", "CPU", "Core(s)", None, None),
|
||||
("cpu-min-max", "CPU", "Core(s)", 1, 20),
|
||||
("ram-1", "RAM", "GB", None, None),
|
||||
("ram-min-max", "RAM", "GB", 1, 200),
|
||||
("matrix-maintenance", "Matrix Maintenance Fee", "", 1, 1),
|
||||
("nextcloud-maintenance", "Nextcloud Maintenance Fee", "", 1, 1),
|
||||
("gitea-maintenance", "Gitea Maintenance Fee", "", 1, 1),
|
||||
# slug name description min max step-size price per 30days
|
||||
("cpu-1", "CPU", "Core(s)", None, None, 0.5, 3),
|
||||
("cpu-min-max", "CPU", "Core(s)", 1, 20, 0.5, 3),
|
||||
("ram-1", "RAM", "GB", None, None, 0.5, 4),
|
||||
("ram-min-max", "RAM", "GB", 1, 200, 0.5, 4),
|
||||
("storage-db", "Database-Storage", "GB", 10, None, 10, 3.5),
|
||||
("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=
|
||||
{
|
||||
"name": res[1],
|
||||
"unit": res[2],
|
||||
"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
|
||||
# for ppt_res in res[5]:
|
||||
# ppt = PricePerTime.objects.get(
|
||||
|
||||
|
||||
# Add test products
|
||||
for product in [
|
||||
("matrix", "Matrix"),
|
||||
("nextcloud", "Nextcloud"),
|
||||
("gitea", "Gitea") ]:
|
||||
Product.objects.get_or_create(slug=product[0],
|
||||
p, created = Product.objects.get_or_create(slug=product[0],
|
||||
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
|
||||
|
||||
price_per_time = models.ManyToManyField(PricePerTime, blank=True)
|
||||
#onetime_price = models.ManyToManyField(OneTimePrice, blank=True)
|
||||
onetime_price = models.ForeignKey(OneTimePrice, null=True, on_delete=models.CASCADE)
|
||||
onetime_price = models.ForeignKey(OneTimePrice,
|
||||
null=True, blank=True,
|
||||
on_delete=models.CASCADE)
|
||||
|
||||
def __str__(self):
|
||||
if self.minimum_units:
|
||||
|
|
|
@ -8,5 +8,5 @@ you to manage all your resources.
|
|||
<h2>What can I do with uncloud?</h2>
|
||||
|
||||
<ul>
|
||||
<li>You can<a href="{% url 'products' %}">order products</a></li>
|
||||
<li>You can <a href="{% url 'products' %}">order products</a></li>
|
||||
</ul>
|
||||
|
|
|
@ -9,5 +9,5 @@
|
|||
<table>
|
||||
{{ form }}
|
||||
</table>
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
<button type="submit" class="btn btn-primary">Order</button>
|
||||
</form>
|
||||
|
|
|
@ -97,6 +97,10 @@ class ProductSelectView(CreateView):
|
|||
fields = ['product' ]
|
||||
|
||||
class IndexView(TemplateView):
|
||||
"""
|
||||
The starting page containing a short intro
|
||||
"""
|
||||
|
||||
template_name = "app/index.html"
|
||||
|
||||
class Yearly(TemplateView):
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
set -x
|
||||
|
||||
name=uncloud:$(git describe)
|
||||
name=ungleich/uncloud:$(git describe)
|
||||
docker build -t ${name} .
|
||||
|
||||
# check for args
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Django basics
|
||||
Django==4.0
|
||||
Django==4.0.5
|
||||
djangorestframework
|
||||
django-auth-ldap
|
||||
|
|
Loading…
Reference in New Issue