Skip to content

Commit

Permalink
add interface to manage webhooks; call webhook
Browse files Browse the repository at this point in the history
  • Loading branch information
kritzl committed Jul 11, 2024
1 parent 7fca44a commit 6b66b9b
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 8 deletions.
15 changes: 15 additions & 0 deletions src/vinywaji/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,18 @@ def create(self, validated_data):
validated_data["amount"] = validated_data["amount"] * -1
validated_data["amount"] = int(validated_data["amount"])
return models.Transaction.objects.create(**validated_data)


class WebhookConfigSerializer(serializers.ModelSerializer):
class Meta:
model = models.WebhookConfig
fields = "__all__"

user = serializers.PrimaryKeyRelatedField(
default=serializers.CurrentUserDefault(), queryset=models.User.objects.all()
)
amount = serializers.FloatField()

def create(self, validated_data):
validated_data["amount"] = int(validated_data["amount"])
return models.WebhookConfig.objects.create(**validated_data)
1 change: 1 addition & 0 deletions src/vinywaji/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
router = routers.SimpleRouter()
router.register(r"users", views.UserViewSet, basename="user")
router.register(r"transactions", views.TransactionViewSet, basename="transaction")
router.register(r"webhooks", views.WebhookConfigViewSet, basename="webhook")


urlpatterns = [
Expand Down
20 changes: 20 additions & 0 deletions src/vinywaji/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,23 @@ def get_permissions(self):
return [IsAuthenticated()]
else:
return [(IsAdminUser | permissions.IsRelatedToRequester)()]


class WebhookConfigViewSet(
viewsets.mixins.CreateModelMixin,
viewsets.mixins.DestroyModelMixin,
viewsets.GenericViewSet,
):
serializer_class = serializers.WebhookConfigSerializer

def get_queryset(self):
if self.request.user.is_superuser:
return models.WebhookConfig.objects.all()
else:
return models.WebhookConfig.objects.filter(user=self.request.user)

def get_permissions(self):
if self.action == "list":
return [IsAuthenticated()]
else:
return [(IsAdminUser | permissions.IsRelatedToRequester)()]
78 changes: 78 additions & 0 deletions src/vinywaji/gui/static/css/dist/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,10 @@ input[type=number] {
grid-column: span 3 / span 3;
}

.col-span-full {
grid-column: 1 / -1;
}

.mx-auto {
margin-left: auto;
margin-right: auto;
Expand All @@ -813,6 +817,11 @@ input[type=number] {
margin-bottom: 1rem;
}

.my-2 {
margin-top: 0.5rem;
margin-bottom: 0.5rem;
}

.mb-8 {
margin-bottom: 2rem;
}
Expand Down Expand Up @@ -845,6 +854,14 @@ input[type=number] {
width: 100%;
}

.min-w-28 {
min-width: 7rem;
}

.min-w-12 {
min-width: 3rem;
}

.grow {
flex-grow: 1;
}
Expand Down Expand Up @@ -882,10 +899,18 @@ input[type=number] {
grid-template-columns: repeat(2, minmax(0, 1fr));
}

.grid-cols-3 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}

.flex-col {
flex-direction: column;
}

.items-center {
align-items: center;
}

.items-stretch {
align-items: stretch;
}
Expand Down Expand Up @@ -922,11 +947,40 @@ input[type=number] {
border-radius: 0.5rem;
}

.border-b {
border-bottom-width: 1px;
}

.border-gray-300 {
--tw-border-opacity: 1;
border-color: rgb(209 213 219 / var(--tw-border-opacity));
}

.border-gray-500 {
--tw-border-opacity: 1;
border-color: rgb(107 114 128 / var(--tw-border-opacity));
}

.border-gray-800 {
--tw-border-opacity: 1;
border-color: rgb(31 41 55 / var(--tw-border-opacity));
}

.border-gray-700 {
--tw-border-opacity: 1;
border-color: rgb(55 65 81 / var(--tw-border-opacity));
}

.border-b-gray-300 {
--tw-border-opacity: 1;
border-bottom-color: rgb(209 213 219 / var(--tw-border-opacity));
}

.border-b-gray-400 {
--tw-border-opacity: 1;
border-bottom-color: rgb(156 163 175 / var(--tw-border-opacity));
}

.bg-black\/10 {
background-color: rgb(0 0 0 / 0.1);
}
Expand Down Expand Up @@ -4856,6 +4910,11 @@ input[type=number] {
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}

.bg-red-400 {
--tw-bg-opacity: 1;
background-color: rgb(248 113 113 / var(--tw-bg-opacity));
}

.px-2 {
padding-left: 0.5rem;
padding-right: 0.5rem;
Expand Down Expand Up @@ -4897,6 +4956,10 @@ input[type=number] {
text-align: center;
}

.align-middle {
vertical-align: middle;
}

.text-2xl {
font-size: 1.5rem;
line-height: 2rem;
Expand Down Expand Up @@ -8895,6 +8958,11 @@ input[type=number] {
background-color: rgb(4 47 46 / 0.95);
}

.hover\:bg-red-500:hover {
--tw-bg-opacity: 1;
background-color: rgb(239 68 68 / var(--tw-bg-opacity));
}

.hover\:text-gray-500:hover {
--tw-text-opacity: 1;
color: rgb(107 114 128 / var(--tw-text-opacity));
Expand Down Expand Up @@ -16854,6 +16922,11 @@ input[type=number] {
background-color: rgb(255 255 255 / 0.1);
}

.dark\:bg-red-600 {
--tw-bg-opacity: 1;
background-color: rgb(220 38 38 / var(--tw-bg-opacity));
}

.dark\:text-gray-400 {
--tw-text-opacity: 1;
color: rgb(156 163 175 / var(--tw-text-opacity));
Expand Down Expand Up @@ -20780,6 +20853,11 @@ input[type=number] {
background-color: rgb(4 47 46 / 0.95);
}

.dark\:hover\:bg-red-700:hover {
--tw-bg-opacity: 1;
background-color: rgb(185 28 28 / var(--tw-bg-opacity));
}

.dark\:focus\:border-blue-500:focus {
--tw-border-opacity: 1;
border-color: rgb(59 130 246 / var(--tw-border-opacity));
Expand Down
4 changes: 2 additions & 2 deletions src/vinywaji/gui/templates/components/forms.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
</button>
{% endmacro %}

{% macro input label name value="" type="text" step="1" min="0" placeholder="" required=False class="" %}
{% macro input label name value="" type="text" step="1" min="" placeholder="" required=False class="" %}
<div class="relative {{ class }}">
<input type="{{ type }}" id="input_{{ name }}"
class="block px-2.5 pb-2.5 pt-4 w-full text-sm text-gray-900 bg-transparent rounded-lg
border-1 border-gray-300 appearance-none dark:text-white dark:border-gray-600
dark:focus:border-blue-500 focus:outline-none focus:ring-0 focus:border-blue-600 peer"
{% if type == 'number' %}inputmode="decimal"{% endif %}
{% if type == 'number' %}step="{{ step }}"{% endif %}
{% if type == 'number' %}min="{{ min }}"{% endif %}
{% if type == 'number' and min %}min="{{ min }}"{% endif %}
{% if required %}required{% endif %}
placeholder="{% if placeholder %}{{ placeholder }}{% else %} {% endif %}"
name="{{ name }}"
Expand Down
16 changes: 16 additions & 0 deletions src/vinywaji/gui/templates/components/forms/add_webhook.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{% load macros %}
{% loadmacros "components/forms.html" %}

<form id="purchase" class="js-submit mt-4 mb-8 sm:mb-2"
action="{% url 'webhook-list' %}" method="post">
{% csrf_token %}
<div class="grid grid-cols-2 justify-stretch gap-2">
{% usemacro input "Description" "description" type="text" class="col-span-full" %}

{% usemacro input "Transaction amount (ct)" "amount" type="number" placeholder="150" required=True step="0.1" %}

{% usemacro input "Transaction description" "transaction_description" type="text" placeholder="fritz-kola" %}

{% usemacro button "Add Webhook" class="col-span-full" %}
</div>
</form>
58 changes: 54 additions & 4 deletions src/vinywaji/gui/templates/views/profile.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,64 @@ <h5 class="text-2xl leading-normal">Basic Information</h5>
<dt class="font-bold">Username:</dt>
<dd>{{ request.user }} </dd>
</div>

</dl>
</section>

<section class="mt-4">
<h5 class="text-2xl leading-normal">Webhooks</h5>
<div>
TODO: Put webhook configuration here
</div>

{% include "components/forms/add_webhook.html" %}

<hr class="border-gray-500 my-4">

{% csrf_token %}

<script>
const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;

async function writeClipboardText(text) {
try {
await navigator.clipboard.writeText(text);
} catch (error) {
console.error(error.message);
}
}

async function deleteWebhook(id) {
await fetch(`{% url 'webhook-list' %}${id}`, {
"method": "DELETE",
headers: {'X-CSRFToken': csrftoken},
}).then(() => {
window.location.reload();
});
}
</script>

<dl>
{% for webhook in webhooks %}
<div class="grid grid-cols-3 gap-2 py-2 border-b border-gray-700">
<dt class="font-bold flex items-center">
{{ webhook.description }}
</dt>
<dd class="col-span-2 flex justify-between items-center">
<div>
<span class="min-w-12 inline-block">{{ webhook.amount }}</span>
<span>{{ webhook.transaction_description }}</span>
</div>
<div>
<button data-key="{{ webhook.trigger_key }}"
onclick="writeClipboardText(`{{ request.scheme }}://{{ request.META.HTTP_HOST }}{% url 'webhook-trigger' trigger=webhook.trigger_key %}`)"
class="text-center bg-primary-400 hover:bg-primary-500 dark:bg-primary-600 dark:hover:bg-primary-700 px-4 py-2 rounded-lg min-w-30">
Copy URL
</button>
<button onclick="deleteWebhook('{{ webhook.id }}')"
class="text-center bg-red-400 hover:bg-red-500 dark:bg-red-600 dark:hover:bg-red-700 px-4 py-2 rounded-lg min-w-30">
Delete
</button>
</div>
</dd>
</div>
{% endfor %}
</dl>
</section>
{% endblock %}
15 changes: 13 additions & 2 deletions src/vinywaji/gui/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from django.shortcuts import render
from django.views import View

from vinywaji.core.models import WebhookConfig


class DashboardView(View):
def get(self, request: HttpRequest):
Expand Down Expand Up @@ -38,14 +40,23 @@ def get(self, request: HttpRequest):
"title": settings.ORG_NAME,
}
if not request.user.is_anonymous:
context.update({})
context.update(
{
"webhooks": request.user.webhooks.all(),
}
)

return render(request, "views/profile.html", context)


class WebhookTriggerView(View):
def get(self, request: HttpRequest, trigger: str):
return HttpResponse("OK")
webhook = WebhookConfig.objects.filter(trigger_key=trigger)
if len(webhook) == 1:
webhook[0].trigger()
return HttpResponse("OK")
else:
return HttpResponse("Failed")


def manifest(request):
Expand Down

0 comments on commit 6b66b9b

Please sign in to comment.