Compare commits
9 commits
1648355fe7
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
ef4ca9d879 | ||
|
6fa10ef6d5 | ||
|
95dfe62858 | ||
|
05eea37349 | ||
51851910c6 | |||
86cb43a3c1 | |||
93013c8997 | |||
|
8668e173b9 | ||
|
a002711885 |
23 changed files with 93 additions and 22 deletions
|
@ -17,6 +17,7 @@ Install system dependencies:
|
|||
|
||||
* On Fedora, you will need the following packages: `python3-virtualenv python3-devel openldap-devel gcc chromium`
|
||||
* sudo apt-get install libpq-dev python-dev libxml2-dev libxslt1-dev libldap2-dev libsasl2-dev libffi-dev
|
||||
* On Archlinux, [libldap24](https://aur.archlinux.org/packages/libldap24) is needed
|
||||
|
||||
|
||||
NOTE: you will need to configure a LDAP server and credentials for authentication. See `uncloud/settings.py`.
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
# While trying to install python-ldap
|
||||
|
||||
FROM python:3.10.0-alpine3.15
|
||||
FROM python:3.11.1-alpine3.17
|
||||
|
||||
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
|
||||
. ./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
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
from django import forms
|
||||
from django.forms import NumberInput
|
||||
|
||||
|
||||
class ProductOneTimeOrderForm(forms.Form):
|
||||
"""
|
||||
|
@ -12,7 +14,22 @@ class ProductOneTimeOrderForm(forms.Form):
|
|||
for res in resources:
|
||||
print(res)
|
||||
field_name = f"{res.slug}"
|
||||
self.fields[field_name] = forms.FloatField(required=True, label=res.name)
|
||||
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()
|
||||
|
@ -21,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:
|
||||
|
|
|
@ -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==5.0.2
|
||||
djangorestframework
|
||||
django-auth-ldap
|
||||
|
|
Loading…
Reference in a new issue