Skip to content

Commit 67f9b4d

Browse files
authored
Merge pull request #21 from jtdub/rest-api
Rest-API Implementation
2 parents 37b3f77 + 0beae67 commit 67f9b4d

File tree

15 files changed

+151
-21
lines changed

15 files changed

+151
-21
lines changed

.pylintrc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
[MESSAGES CONTROL]
2-
disable=no-member
2+
disable=no-member,too-few-public-methods,too-many-ancestors

netopsio/home/serializers.py

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Home App and Worker Serializers."""
2+
from rest_framework import serializers
3+
from django_celery_results.models import TaskResult
4+
5+
6+
class TaskResultSerializer(serializers.HyperlinkedModelSerializer):
7+
"""TaskResult Serializer."""
8+
9+
url = serializers.HyperlinkedIdentityField(
10+
view_name="taskresult-detail", lookup_field="task_id"
11+
)
12+
13+
class Meta:
14+
"""Task Result Serializer Meta."""
15+
16+
model = TaskResult
17+
fields = [
18+
"task_id",
19+
"task_name",
20+
"task_kwargs",
21+
"status",
22+
"result",
23+
"date_created",
24+
"date_done",
25+
"url",
26+
]

netopsio/home/templates/home/result_details.html netopsio/home/templates/home/task_details.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
{% block content %}
33
<div class="container">
44
<div class="mb-3">
5-
<label for="statusArea" class="form-label"><h3>Job Status</h3></label>
5+
<label for="statusArea" class="form-label"><h3>Status</h3></label>
66
<input type="input" class="form-control" id="statusArea" placeholder="{{ job.status }}">
77
</div>
88
<div class="mb-3">

netopsio/home/templates/home/results.html netopsio/home/templates/home/tasks.html

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
<table class="table">
55
<thead>
66
<th scope="col">ID</th>
7-
<th scope="col">Task Name</th>
8-
<th scope="col">Task Status</th>
7+
<th scope="col">Name</th>
8+
<th scope="col">Status</th>
99
<th scope="col">Keyword Arguments</th>
1010
</thead>
1111
<tbody>
1212
{% for task in results %}
1313
<tr>
14-
<th scope="row"><a href="/results/{{ task.task_id }}">{{ task.task_id }}</a></th>
14+
<th scope="row"><a href="/tasks/{{ task.task_id }}">{{ task.task_id }}</a></th>
1515
<td>{{ task.task_name }}</td>
1616
<td>{{ task.status }}</td>
1717
<td>{{ task.task_kwargs }}</td>

netopsio/home/urls.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
app_name = "" # pylint: disable=invalid-name
66
urlpatterns = [
7-
path("", views.index, name="home_index"),
8-
path("results/", views.results, name="home_results"),
9-
path("results/<str:task_id>/", views.result_details, name="results_details"),
7+
path("", views.index, name="home-index"),
8+
path("tasks/", views.tasks, name="tasks"),
9+
path("tasks/<str:task_id>/", views.task_details, name="task-details"),
1010
]

netopsio/home/views.py

+15-5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
from django.template import loader
44
from django.shortcuts import get_object_or_404
55
from django_celery_results.models import TaskResult
6+
from rest_framework import viewsets
7+
from home.serializers import TaskResultSerializer
68

79

810
def index(request):
@@ -12,17 +14,25 @@ def index(request):
1214
return HttpResponse(template.render(context, request))
1315

1416

15-
def results(request):
17+
def tasks(request):
1618
"""Render Task Results."""
1719
task_results = TaskResult.objects.all()
18-
template = loader.get_template("home/results.html")
20+
template = loader.get_template("home/tasks.html")
1921
context = {"title": "Task Results", "results": task_results}
2022
return HttpResponse(template.render(context, request))
2123

2224

23-
def result_details(request, task_id):
25+
def task_details(request, task_id):
2426
"""Render Task Detail Results."""
2527
job = get_object_or_404(TaskResult, task_id=task_id)
26-
template = loader.get_template("home/result_details.html")
27-
context = {"title": "Task Result Details", "job": job}
28+
template = loader.get_template("home/task_details.html")
29+
context = {"title": "Task Details", "job": job}
2830
return HttpResponse(template.render(context, request))
31+
32+
33+
class TaskResultViewSet(viewsets.ModelViewSet):
34+
"""Rest API View for 'list' and 'retrieving' TaskResult actions."""
35+
36+
queryset = TaskResult.objects.all()
37+
serializer_class = TaskResultSerializer
38+
lookup_field = "task_id"

netopsio/netopsio/settings.py

+7
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"django.contrib.sessions",
3939
"django.contrib.messages",
4040
"django.contrib.staticfiles",
41+
"rest_framework",
4142
"django_celery_results",
4243
"home",
4344
"ping",
@@ -141,3 +142,9 @@
141142
CELERY_TASK_TIME_LIMIT = 30 * 60
142143

143144
CELERY_RESULT_BACKEND = "django-db"
145+
146+
# Rest Framework Settings
147+
REST_FRAMEWORK = {
148+
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
149+
"PAGE_SIZE": 10,
150+
}

netopsio/netopsio/urls.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,20 @@
1616
from django.contrib import admin
1717
from django.urls import include, path
1818

19+
from rest_framework.routers import DefaultRouter
20+
from home.views import TaskResultViewSet
21+
from ping.views import PingRequestViewSet, PingViewSet
22+
23+
24+
router = DefaultRouter()
25+
router.register(r"tasks", TaskResultViewSet)
26+
router.register(r"ping-logs", PingRequestViewSet)
27+
router.register(r"ping", PingViewSet, basename="ping")
28+
29+
1930
urlpatterns = [
2031
path("", include("home.urls"), name="home"),
2132
path("ping/", include("ping.urls"), name="ping"),
22-
path("admin/", admin.site.urls),
33+
path("admin/", admin.site.urls, name="admin"),
34+
path("api/v1/", include(router.urls), name="admin-v1"),
2335
]

netopsio/ping/models.py

+8
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,11 @@ class PingRequest(models.Model):
1010
task_id = models.UUIDField(unique=True, null=True)
1111
ip = models.CharField(max_length=255)
1212
result = models.TextField()
13+
14+
15+
class Ping:
16+
"""Ping Model."""
17+
18+
def __init__(self, task_id: str):
19+
"""Initialize the model."""
20+
self.task_id = task_id

netopsio/ping/serializers.py

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"""Ping App serializers."""
2+
3+
from rest_framework import serializers
4+
from ping.models import PingRequest
5+
6+
7+
class PingRequestSerializer(serializers.ModelSerializer):
8+
"""PingRequest Serializer."""
9+
10+
class Meta:
11+
"""PingRequest Serializer Meta."""
12+
13+
model = PingRequest
14+
fields = ["id", "date", "task_id", "ip", "result", "url"]
15+
16+
17+
class PingSerializer(serializers.Serializer): # pylint: disable=abstract-method
18+
"""Ping Serializer."""
19+
20+
task_id = serializers.CharField(max_length=512)

netopsio/ping/templates/ping/base.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<tbody>
1010
<tr>
1111
<td>{{ status }}</td>
12-
<td><a href="/results/{{ id }}/">{{ host }}</a></td>
12+
<td><a href="/tasks/{{ id }}/">{{ host }}</a></td>
1313
</tr>
1414
</tbody>
1515
</table>

netopsio/ping/urls.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44

55
app_name = "" # pylint: disable=invalid-name
66
urlpatterns = [
7-
path("", views.index, name="ping_index"),
7+
path("", views.index, name="ping-index"),
88
]

netopsio/ping/views.py

+38-4
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,49 @@
22
from django.http import HttpResponse
33
from django.template import loader
44
from ping.tasks import ping
5+
from ping.models import PingRequest, Ping
6+
from ping.serializers import PingRequestSerializer, PingSerializer
7+
from rest_framework import viewsets
8+
from rest_framework.response import Response
59

610

711
def index(request):
812
"""Ping app index view."""
9-
if "HTTP_X_FORWARDED_FOR" in request.META:
10-
host = request.META["HTTP_X_FORWARDED_FOR"]
11-
else:
12-
host = request.META["REMOTE_ADDR"]
13+
host = request.GET.get("host")
14+
15+
if host is None:
16+
if "HTTP_X_FORWARDED_FOR" in request.META:
17+
host = request.META["HTTP_X_FORWARDED_FOR"]
18+
else:
19+
host = request.META["REMOTE_ADDR"]
20+
1321
task = ping.delay(host=host)
1422
template = loader.get_template("ping/base.html")
1523
context = {"host": host, "status": task.status, "id": task, "title": "Ping"}
1624
return HttpResponse(template.render(context, request))
25+
26+
27+
class PingRequestViewSet(viewsets.ReadOnlyModelViewSet):
28+
"""Rest API View for 'list' and 'retrieving' PingRequest actions."""
29+
30+
queryset = PingRequest.objects.all()
31+
serializer_class = PingRequestSerializer
32+
33+
34+
class PingViewSet(viewsets.ViewSet):
35+
"""Ping Viewset."""
36+
37+
def create(self, request): # pylint: disable=no-self-use
38+
"""CREATE view."""
39+
host = request.POST.get("host")
40+
41+
if host is None:
42+
if "HTTP_X_FORWARDED_FOR" in request.META:
43+
host = request.META["HTTP_X_FORWARDED_FOR"]
44+
else:
45+
host = request.META["REMOTE_ADDR"]
46+
47+
task = ping.delay(host=host)
48+
data = Ping(task_id=task.task_id)
49+
serializer = PingSerializer(data, context={"request": request})
50+
return Response(serializer.data)

netopsio/templates/base.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
2020
<div class="navbar-nav">
2121
<a class="nav-link" href="/">Home</a>
22-
<a class="nav-link" href="/results/">Task Results</a>
22+
<a class="nav-link" href="/tasks/">Task Results</a>
2323
<a class="nav-link" href="/ping/">Ping Application</a>
2424
</div>
2525
</div>

tasks.py

+13
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,16 @@ def migrate(context, container="app"):
192192
"""Perform migrate operation in Django."""
193193
command = "python manage.py migrate"
194194
docker_compose(context, f"exec {container} {command}", pty=True)
195+
196+
197+
@task
198+
def shell(context, container="app"):
199+
"""Enter the Django Shell."""
200+
command = "python manage.py shell"
201+
docker_compose(context, f"exec {container} {command}", pty=True)
202+
203+
204+
@task
205+
def logs(context, container="app"):
206+
"""Enter the Django Shell."""
207+
docker_compose(context, f"logs {container}", pty=True)

0 commit comments

Comments
 (0)