Compare commits

...

10 commits

15 changed files with 535 additions and 105 deletions

View file

@ -0,0 +1,18 @@
# Generated by Django 5.1.5 on 2025-03-03 16:52
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("services", "0016_cloudprovider_disable_listing_and_more"),
]
operations = [
migrations.AddField(
model_name="service",
name="tagline",
field=models.TextField(blank=True, max_length=500, null=True),
),
]

View file

@ -116,6 +116,7 @@ class Service(models.Model):
name = models.CharField(max_length=200)
slug = models.SlugField(max_length=250, unique=True)
description = ProseEditorField()
tagline = models.TextField(max_length=500, blank=True, null=True)
logo = models.ImageField(
upload_to="service_logos/",
validators=[validate_image_size],

View file

@ -8,6 +8,13 @@
{% if details %}
<input type="hidden" name="details" value="{{ details }}">
{% endif %}
<input type="hidden" name="form_timestamp" value="{{ request.timestamp|default:timestamp }}">
<div style="display:none;">
<label for="website">Website (Leave this empty)</label>
<input type="text" name="website" id="website" autocomplete="off">
</div>
{% if service %}
<input type="hidden" name="service_id" value="{{ service.id }}">
<input type="hidden" name="service_name" value="{{ service.name }}">
@ -54,6 +61,17 @@
{% endif %}
</div>
{% if choices %}
<div class="mb-3">
<label for="id_choice" class="form-label">{{ choice_label|default:"Please Select" }}</label>
<select name="selected_choice" id="id_choice" class="form-control">
{% for choice_id, choice_name in choices %}
<option value="{{ choice_id }}|{{ choice_name }}">{{ choice_name }}</option>
{% endfor %}
</select>
</div>
{% endif %}
<div class="mb-3">
<label for="id_message" class="form-label">Your Message (Optional)</label>
{{ form.message|addclass:"form-control" }}

View file

@ -1,7 +1,7 @@
{% extends 'services/base.html' %}
{% load static %}
{% block title %}The Cloud Native Services Hub{% endblock %}
{% block title %}Open Cloud Native Services Hub{% endblock %}
{% block content %}
<section class="section section-hero bg-primary-subtle">
@ -9,7 +9,7 @@
<div class="section-hero-mask"></div>
<div class="px-3 px-lg-0 pt-80 pb-120 position-relative">
<header class="section-hero__header">
<h1 class="section-h1 fs-40 fs-lg-64">Servala - The Cloud Native Service Hub</h1>
<h1 class="section-h1 fs-40 fs-lg-64">Servala - Open Cloud Native Service Hub</h1>
<div class="section-hero__desc">
<p>Unlock the Power of Cloud Native Applications.</p>
<p>Servala connects businesses, developers, and cloud service providers on one unique hub with secure, scalable, and easy-to-use cloud-native services.</p>
@ -169,7 +169,7 @@
</div>
<div class="col-12 col-lg-8">
<header class="section-primary__header">
<h2 class="section-h1 fs-40 fs-lg-60">Servala - The Cloud Native Service Hub</h2>
<h2 class="section-h1 fs-40 fs-lg-60">Servala - Open Cloud Native Service Hub</h2>
<div class="section-primary__desc">
<p>Servala connects businesses, developers, and cloud service providers on one unique hub with secure, scalable, and easy-to-use cloud-native services.</p>
<p>Discover:</p>

View file

@ -149,11 +149,6 @@
</div>
{% endif %}
</div>
<div>
<h4 class="mb-3">Order This Plan</h4>
{% load contact_tags %}
{% embedded_contact_form source="Plan Order" service=offering.service offering_id=offering.id plan_id=plan.id %}
</div>
</div>
</div>
{% empty %}
@ -167,6 +162,18 @@
</div>
{% endfor %}
</div>
{% if offering.plans.exists %}
<div class="pt-40">
<h4 class="fs-22 fw-semibold lh-1 mb-12">I'm interested in a plan</h4>
<div class="row">
<div class="col-12">
{% load contact_tags %}
{% embedded_contact_form source="Plan Order" service=offering.service offering_id=offering.id choices=offering.plans.all choice_label="Select a Plan" %}
</div>
</div>
</div>
{% endif %}
</div>
</div>
</div>

View file

@ -85,7 +85,7 @@
<div>
<select class="form-select" id="service" name="service" @change="submitForm()">
<option value="">All Services</option>
{% for service in services %}
{% for service in available_services %}
<option value="{{ service.id }}" {% if request.GET.service == service.id|stringformat:'i' %}selected{% endif %}>
{{ service.name }}
</option>
@ -94,23 +94,6 @@
</div>
</div>
<!-- Cloud Provider Filter -->
<div class="pt-24 mb-24">
<div class="d-flex justify-content-between align-items-center h-33 mb-5px" role="button">
<h3 class="sidebar-title mb-0">Cloud Provider</h3>
</div>
<div>
<select class="form-select" id="cloud_provider" name="cloud_provider" @change="submitForm()">
<option value="">All Providers</option>
{% for provider in cloud_providers %}
<option value="{{ provider.id }}" {% if request.GET.cloud_provider == provider.id|stringformat:'i' %}selected{% endif %}>
{{ provider.name }}
</option>
{% endfor %}
</select>
</div>
</div>
<!-- Filter Actions -->
<div class="d-flex gap-2">
<a href="{% url 'services:partner_list' %}" class="btn btn-outline-secondary btn-sm">Clear</a>

View file

@ -106,6 +106,13 @@
<button class="btn btn-tertiary btn-sm mr-12">{{ category.full_path }}</button>
{% endfor %}
</div>
{% if service.tagline %}
<div class="mt-3">
<p class="fst-italic text-muted fs-19">
"{{ service.tagline }}"
</p>
</div>
{% endif %}
</div>
<!-- Description -->

View file

@ -86,12 +86,12 @@
<div>
<select class="form-select" id="category" name="category" @change="submitForm()">
<option value="">All Categories</option>
{% for category in categories %}
{% for category in available_categories %}
<option value="{{ category.id }}" {% if request.GET.category == category.id|stringformat:'i' %}selected{% endif %}>
{{ category.name }}
</option>
{% if category.children.all %}
{% for subcategory in category.children.all %}
{% if category.available_children %}
{% for subcategory in category.available_children %}
<option value="{{ subcategory.id }}" {% if request.GET.category == subcategory.id|stringformat:'i' %}selected{% endif %}>
&nbsp;&nbsp;&nbsp;{{ subcategory.name }}
</option>
@ -110,7 +110,7 @@
<div>
<select class="form-select" id="consulting_partner" name="consulting_partner" @change="submitForm()">
<option value="">All Partners</option>
{% for partner in consulting_partners %}
{% for partner in available_consulting_partners %}
<option value="{{ partner.id }}" {% if request.GET.consulting_partner == partner.id|stringformat:'i' %}selected{% endif %}>
{{ partner.name }}
</option>
@ -127,7 +127,7 @@
<div>
<select class="form-select" id="cloud_provider" name="cloud_provider" @change="submitForm()">
<option value="">All Providers</option>
{% for provider in cloud_providers %}
{% for provider in available_cloud_providers %}
<option value="{{ provider.id }}" {% if request.GET.cloud_provider == provider.id|stringformat:'i' %}selected{% endif %}>
{{ provider.name }}
</option>
@ -179,6 +179,11 @@
<span>{{ category.full_path }}</span>
{% endfor %}
</p>
{% if service.tagline %}
<p class="card__tagline fst-italic text-muted">
<small>"{{ service.tagline }}"</small>
</p>
{% endif %}
</div>
<div class="card__desc flex-grow-1">
<p class="mb-0">{{ service.description|safe|truncatewords:30 }}</p>

View file

@ -2,13 +2,21 @@
from django import template
from hub.services.forms import LeadForm
from hub.services.models import Service, ServiceOffering, Plan
import time
register = template.Library()
@register.inclusion_tag("services/embedded_contact_form.html", takes_context=True)
def embedded_contact_form(
context, source=None, details=None, service=None, offering_id=None, plan_id=None
context,
source=None,
details=None,
service=None,
offering_id=None,
plan_id=None,
choices=None,
choice_label=None,
):
"""
Renders an embedded contact form with optional service context information.
@ -17,14 +25,23 @@ def embedded_contact_form(
{% load contact_tags %}
{% embedded_contact_form source="Partner Page" details="ACME Corp" %}
{% embedded_contact_form service=service offering_id=offering.id plan_id=plan.id %}
{% embedded_contact_form service=service offering_id=offering.id choices=offering.plans.all choice_label="Select a Plan" %}
"""
request = context["request"]
form = LeadForm()
# Add timestamp for spam protection
timestamp = int(time.time())
service_obj = None
offering_obj = None
plan_obj = None
# Process choices if they're QuerySet objects (like plans)
processed_choices = None
if choices:
processed_choices = [(str(choice.id), choice.name) for choice in choices]
# Resolve service/offering/plan objects if IDs provided
if service and isinstance(service, str):
try:
@ -56,4 +73,7 @@ def embedded_contact_form(
"offering": offering_obj,
"plan": plan_obj,
"request": request,
"choices": processed_choices,
"choice_label": choice_label,
"timestamp": timestamp,
}

View file

@ -0,0 +1,228 @@
# hub/services/templatetags/json_ld_tags.py
from django import template
from django.urls import resolve
from django.utils.safestring import mark_safe
import json
register = template.Library()
@register.simple_tag(takes_context=True)
def json_ld_structured_data(context):
"""
Generates appropriate JSON-LD structured data based on the current page.
"""
request = context["request"]
current_url = request.path
resolved_view = resolve(current_url)
view_name = resolved_view.url_name
# Base URL for building absolute URLs
base_url = request.build_absolute_uri("/").rstrip("/")
# Default organization data (for Servala)
organization_data = {
"@context": "https://schema.org",
"@type": "Organization",
"name": "Servala",
"url": base_url,
"logo": f"{base_url}/static/img/header-logo.png",
"contactPoint": {
"@type": "ContactPoint",
"telephone": "+41 44 545 53 00",
"email": "hi@serva.la",
"contactType": "Customer Support",
},
"address": {
"@type": "PostalAddress",
"streetAddress": "Neugasse 10",
"addressLocality": "Zurich",
"postalCode": "8005",
"addressCountry": "CH",
},
}
# Handle different page types
if view_name == "homepage":
data = {
"@context": "https://schema.org",
"@type": "WebSite",
"name": "Servala - Open Cloud Native Service Hub",
"url": base_url,
"description": "Servala connects businesses, developers, and cloud service providers on one unique hub with secure, scalable, and easy-to-use cloud-native services.",
"potentialAction": {
"@type": "SearchAction",
"target": f"{base_url}/services/?search={{search_term_string}}",
"query-input": "required name=search_term_string",
},
}
elif view_name == "service_list":
data = {
"@context": "https://schema.org",
"@type": "CollectionPage",
"name": "Cloud Services - Servala",
"url": f"{base_url}/services/",
"description": "Explore all available cloud services on Servala, with new services added regularly.",
"isPartOf": {"@type": "WebSite", "name": "Servala", "url": base_url},
}
elif view_name == "provider_list":
data = {
"@context": "https://schema.org",
"@type": "CollectionPage",
"name": "Cloud Providers - Servala",
"url": f"{base_url}/providers/",
"description": "Discover cloud providers on Servala offering reliable infrastructure and innovative cloud computing solutions.",
"isPartOf": {"@type": "WebSite", "name": "Servala", "url": base_url},
}
elif view_name == "partner_list":
data = {
"@context": "https://schema.org",
"@type": "CollectionPage",
"name": "Consulting Partners - Servala",
"url": f"{base_url}/partners/",
"description": "Browse our network of expert consulting partners on Servala who can help implement and optimize cloud services.",
"isPartOf": {"@type": "WebSite", "name": "Servala", "url": base_url},
}
elif view_name == "service_detail" and "service" in context:
service = context["service"]
service_url = request.build_absolute_uri()
data = {
"@context": "https://schema.org",
"@type": "Product",
"name": service.name,
"description": service.description,
"url": service_url,
"category": "Cloud Service",
}
# Add image if available
if hasattr(service, "logo") and service.logo:
data["image"] = request.build_absolute_uri(service.logo.url)
# Add offerings if available
if hasattr(service, "offerings") and service.offerings.exists():
data["offers"] = {
"@type": "AggregateOffer",
"availability": "https://schema.org/InStock",
"offerCount": service.offerings.count(),
}
elif view_name == "provider_detail" and "provider" in context:
provider = context["provider"]
provider_url = request.build_absolute_uri()
data = {
"@context": "https://schema.org",
"@type": "Organization",
"name": provider.name,
"description": provider.description,
"url": provider_url,
}
# Add image if available
if hasattr(provider, "logo") and provider.logo:
data["logo"] = request.build_absolute_uri(provider.logo.url)
# Add contact information if available
contact_point = {"@type": "ContactPoint", "contactType": "Customer Support"}
if hasattr(provider, "website") and provider.website:
contact_point["url"] = provider.website
if hasattr(provider, "email") and provider.email:
contact_point["email"] = provider.email
if hasattr(provider, "phone") and provider.phone:
contact_point["telephone"] = provider.phone
if len(contact_point) > 2: # If we have more than the @type and contactType
data["contactPoint"] = contact_point
# Add address if available
if hasattr(provider, "address") and provider.address:
data["address"] = {
"@type": "PostalAddress",
"addressCountry": "CH", # Default to Switzerland
}
elif view_name == "partner_detail" and "partner" in context:
partner = context["partner"]
partner_url = request.build_absolute_uri()
data = {
"@context": "https://schema.org",
"@type": "Organization",
"name": partner.name,
"description": partner.description,
"url": partner_url,
}
# Add image if available
if hasattr(partner, "logo") and partner.logo:
data["logo"] = request.build_absolute_uri(partner.logo.url)
# Add contact information if available
contact_point = {"@type": "ContactPoint", "contactType": "Customer Support"}
if hasattr(partner, "website") and partner.website:
contact_point["url"] = partner.website
if hasattr(partner, "email") and partner.email:
contact_point["email"] = partner.email
if hasattr(partner, "phone") and partner.phone:
contact_point["telephone"] = partner.phone
if len(contact_point) > 2: # If we have more than the @type and contactType
data["contactPoint"] = contact_point
# Add address if available
if hasattr(partner, "address") and partner.address:
data["address"] = {
"@type": "PostalAddress",
"addressCountry": "CH", # Default to Switzerland
}
elif view_name == "offering_detail" and "offering" in context:
offering = context["offering"]
offering_url = request.build_absolute_uri()
data = {
"@context": "https://schema.org",
"@type": "Product",
"name": f"{offering.service.name} on {offering.cloud_provider.name}",
"description": offering.description or offering.service.description,
"url": offering_url,
"category": "Cloud Service",
}
# Add brand (service)
data["brand"] = {"@type": "Brand", "name": offering.service.name}
# Add image if available
if hasattr(offering.service, "logo") and offering.service.logo:
data["image"] = request.build_absolute_uri(offering.service.logo.url)
# Add offers if available
if hasattr(offering, "plans") and offering.plans.exists():
data["offers"] = {
"@type": "AggregateOffer",
"availability": "https://schema.org/InStock",
"offerCount": offering.plans.count(),
"seller": {
"@type": "Organization",
"name": offering.cloud_provider.name,
"url": request.build_absolute_uri(
offering.cloud_provider.get_absolute_url()
),
},
}
else:
# Default to organization data if no specific page type matches
data = organization_data
# Return the JSON-LD as a script tag
json_ld = json.dumps(data, indent=2)
return mark_safe(f'<script type="application/ld+json">{json_ld}</script>')

View file

@ -1,5 +1,5 @@
from django import template
from django.urls import resolve
from django.urls import resolve, Resolver404
from django.utils.safestring import mark_safe
register = template.Library()
@ -12,8 +12,12 @@ def social_meta_tags(context):
"""
request = context["request"]
current_url = request.path
resolved_view = resolve(current_url)
view_name = resolved_view.url_name
try:
resolved_view = resolve(current_url)
view_name = resolved_view.view_name
except Resolver404:
view_name = None
# Default values (used for listing pages)
title = context.get("self.title", "Servala")

View file

@ -1,4 +1,5 @@
import logging
import time
from django.shortcuts import render, redirect
from django.contrib import messages
@ -18,6 +19,27 @@ def thank_you(request):
def contact_form(request):
if request.method == "POST":
# Spam protection checks
honeypot_value = request.POST.get("website", "")
timestamp_value = request.POST.get("form_timestamp", "0")
current_time = int(time.time())
# Check 1: Honeypot field should be empty
if honeypot_value:
# Bot detected - silently redirect
return redirect("services:homepage")
# Check 2: Form shouldn't be submitted too quickly (< 3 seconds)
try:
form_time = int(timestamp_value)
if current_time - form_time < 3:
# Too quick submission - likely a bot
return redirect("services:homepage")
except ValueError:
# Invalid timestamp - likely a bot
return redirect("services:homepage")
# Continue with normal form processing
form = LeadForm(request.POST)
if form.is_valid():
from hub.services.models import Lead, Service, ServiceOffering, Plan
@ -26,7 +48,7 @@ def contact_form(request):
lead = Lead(
name=form.cleaned_data["name"],
email=form.cleaned_data["email"],
message=form.cleaned_data["message"],
message=form.cleaned_data["message"] or "",
company=form.cleaned_data["company"],
phone=form.cleaned_data["phone"],
)
@ -87,6 +109,22 @@ def contact_form(request):
if plan_name:
service_info.append(f"Plan: {plan_name}")
# Handle selected choice if present
selected_choice = request.POST.get("selected_choice", "")
if selected_choice:
try:
choice_id, choice_name = selected_choice.split("|", 1)
# Add selected choice to message
service_info.append(f"Selected Plan: {choice_name}")
# Try to set the plan based on the choice_id
try:
lead.plan = Plan.objects.get(id=choice_id)
except Plan.DoesNotExist:
pass
except ValueError:
pass
if service_info:
context_info.append("Service Information: " + ", ".join(service_info))

View file

@ -4,35 +4,70 @@ from hub.services.models import ConsultingPartner, CloudProvider, Service
def partner_list(request):
partners = (
ConsultingPartner.objects.filter(disable_listing=False)
.order_by("name")
.prefetch_related("services", "cloud_providers")
)
# Get basic filter parameters
search_query = request.GET.get("search", "")
service_id = request.GET.get("service", "")
cloud_provider_id = request.GET.get("cloud_provider", "")
services = Service.objects.all().order_by("name")
# Start with all active partners
partners = ConsultingPartner.objects.filter(disable_listing=False).order_by("name")
# Handle cloud provider filter
if request.GET.get("cloud_provider"):
provider_id = request.GET.get("cloud_provider")
partners = partners.filter(cloud_providers__id=provider_id)
# Handle service filter
if request.GET.get("service"):
service_id = request.GET.get("service")
partners = partners.filter(services__id=service_id)
# Handle search
if request.GET.get("search"):
query = request.GET.get("search")
# Apply filters based on request parameters
if search_query:
partners = partners.filter(
Q(name__icontains=query) | Q(description__icontains=query)
Q(name__icontains=search_query) | Q(description__icontains=search_query)
)
if service_id:
partners = partners.filter(services__id=service_id)
if cloud_provider_id:
partners = partners.filter(cloud_providers__id=cloud_provider_id)
# Get available services from filtered partners
available_service_ids = partners.values_list("services__id", flat=True).distinct()
available_services = Service.objects.filter(
id__in=available_service_ids, disable_listing=False
).order_by("name")
# Get available cloud providers from filtered partners
available_cloud_provider_ids = partners.values_list(
"cloud_providers__id", flat=True
).distinct()
available_cloud_providers = CloudProvider.objects.filter(
id__in=available_cloud_provider_ids, disable_listing=False
).order_by("name")
# For the current selection, we need to make sure we include the selected items
# even if they don't match other filters
if service_id:
try:
selected_service_id = int(service_id)
if selected_service_id not in available_service_ids:
selected_service = Service.objects.get(id=selected_service_id)
available_services = list(available_services)
available_services.append(selected_service)
except (ValueError, Service.DoesNotExist):
pass
if cloud_provider_id:
try:
cp_id = int(cloud_provider_id)
if cp_id not in available_cloud_provider_ids:
selected_provider = CloudProvider.objects.get(id=cp_id)
available_cloud_providers = list(available_cloud_providers)
available_cloud_providers.append(selected_provider)
except (ValueError, CloudProvider.DoesNotExist):
pass
context = {
"partners": partners,
"services": services,
"cloud_providers": CloudProvider.objects.all(),
"partners": partners.prefetch_related("services", "cloud_providers"),
"services": Service.objects.filter(disable_listing=False).order_by("name"),
"cloud_providers": CloudProvider.objects.filter(disable_listing=False).order_by(
"name"
),
"available_services": available_services,
"available_cloud_providers": available_cloud_providers,
}
return render(request, "services/partner_list.html", context)

View file

@ -9,55 +9,121 @@ from hub.services.models import (
def service_list(request):
services = (
Service.objects.filter(disable_listing=False)
.order_by("-is_featured", "is_coming_soon", "name")
.prefetch_related(
"categories",
"offerings",
"offerings__cloud_provider",
"offerings__plans",
"consulting_partners",
"external_links",
# Get basic filter parameters
search_query = request.GET.get("search", "")
category_id = request.GET.get("category", "")
consulting_partner_id = request.GET.get("consulting_partner", "")
cloud_provider_id = request.GET.get("cloud_provider", "")
# Start with all active services
# Filter out services with disable_listing=True
services = Service.objects.filter(disable_listing=False)
# Apply filters based on request parameters
if search_query:
services = services.filter(
Q(name__icontains=search_query) | Q(description__icontains=search_query)
)
if category_id:
services = services.filter(categories__id=category_id)
if consulting_partner_id:
services = services.filter(consulting_partners__id=consulting_partner_id)
if cloud_provider_id:
# Filter through offerings instead of direct cloud_providers relation
services = services.filter(offerings__cloud_provider__id=cloud_provider_id)
# Order services: featured first, then regular services, then coming soon
services = services.order_by(
"-is_featured", # Featured first (True before False)
"is_coming_soon", # Coming soon last (False before True)
"name", # Alphabetically within each group
)
cloud_providers = CloudProvider.objects.all()
categories = Category.objects.filter(parent=None).prefetch_related("children")
# Handle category filter
if request.GET.get("category"):
category_id = request.GET.get("category")
category = get_object_or_404(Category, id=category_id)
subcategories = Category.objects.filter(parent=category)
services = services.filter(
Q(categories=category) | Q(categories__in=subcategories)
).distinct()
# Get all available categories from filtered services
available_category_ids = services.values_list(
"categories__id", flat=True
).distinct()
available_categories = Category.objects.filter(
id__in=available_category_ids, parent=None
)
# Handle cloud provider filter
if request.GET.get("cloud_provider"):
provider_id = request.GET.get("cloud_provider")
services = services.filter(offerings__cloud_provider_id=provider_id).distinct()
# For each parent category, get available children
for category in available_categories:
child_ids = (
services.filter(categories__parent=category)
.values_list("categories__id", flat=True)
.distinct()
)
category.available_children = Category.objects.filter(id__in=child_ids)
# Handle consulting partner filter
if request.GET.get("consulting_partner"):
partner_id = request.GET.get("consulting_partner")
services = services.filter(consulting_partners__id=partner_id).distinct()
# Get available consulting partners from filtered services
# Excluding partners with disable_listing=True
available_consulting_partner_ids = services.values_list(
"consulting_partners__id", flat=True
).distinct()
available_consulting_partners = ConsultingPartner.objects.filter(
id__in=available_consulting_partner_ids, disable_listing=False
)
# Handle search
if request.GET.get("search"):
query = request.GET.get("search")
services = services.filter(
Q(name__icontains=query)
| Q(description__icontains=query)
| Q(offerings__description__icontains=query)
).distinct()
# Get available cloud providers from filtered services via offerings
# Excluding providers with disable_listing=True
available_cloud_provider_ids = services.values_list(
"offerings__cloud_provider__id", flat=True
).distinct()
available_cloud_providers = CloudProvider.objects.filter(
id__in=available_cloud_provider_ids, disable_listing=False
)
# For the current selection, we need to make sure we include the selected items
# even if they don't match other filters
if category_id:
try:
selected_category = Category.objects.get(id=category_id)
if selected_category.parent:
parent_category = selected_category.parent
if parent_category not in available_categories:
available_categories = list(available_categories)
available_categories.append(parent_category)
parent_category.available_children = [selected_category]
elif selected_category not in available_categories:
available_categories = list(available_categories)
available_categories.append(selected_category)
except Category.DoesNotExist:
pass
if consulting_partner_id:
try:
cp_id = int(consulting_partner_id)
if cp_id not in available_consulting_partner_ids:
selected_partner = ConsultingPartner.objects.get(id=cp_id)
available_consulting_partners = list(available_consulting_partners)
available_consulting_partners.append(selected_partner)
except (ValueError, ConsultingPartner.DoesNotExist):
pass
if cloud_provider_id:
try:
cp_id = int(cloud_provider_id)
if cp_id not in available_cloud_provider_ids:
selected_provider = CloudProvider.objects.get(id=cp_id)
available_cloud_providers = list(available_cloud_providers)
available_cloud_providers.append(selected_provider)
except (ValueError, CloudProvider.DoesNotExist):
pass
context = {
"services": services,
"cloud_providers": cloud_providers,
"categories": categories,
"consulting_partners": ConsultingPartner.objects.all(),
"categories": Category.objects.filter(parent=None),
"consulting_partners": ConsultingPartner.objects.filter(disable_listing=False),
"cloud_providers": CloudProvider.objects.filter(disable_listing=False),
"available_categories": available_categories,
"available_consulting_partners": available_consulting_partners,
"available_cloud_providers": available_cloud_providers,
}
return render(request, "services/service_list.html", context)

View file

@ -42,6 +42,13 @@ urlpatterns = [
path("admin/", admin.site.urls),
path("", include("hub.services.urls")),
path("broker/", include("hub.broker.urls", namespace="broker")),
path(
"sitemap.xml",
sitemap,
{"sitemaps": sitemaps},
name="django.contrib.sitemaps.views.sitemap",
),
path("robots.txt", robots_txt, name="robots_txt"),
]
if settings.DEBUG:
urlpatterns += [
@ -50,12 +57,5 @@ if settings.DEBUG:
path("test-400/", lambda request: render(request, "400.html"), name="test_400"),
path("test-404/", lambda request: render(request, "404.html"), name="test_404"),
path("test-500/", lambda request: render(request, "500.html"), name="test_500"),
path(
"sitemap.xml",
sitemap,
{"sitemaps": sitemaps},
name="django.contrib.sitemaps.views.sitemap",
),
path("robots.txt", robots_txt, name="robots_txt"),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)