From 37c10284f1e46db0dd199c7fdd8f2fb9acaf7a8b Mon Sep 17 00:00:00 2001 From: Kumi Date: Tue, 20 Sep 2022 14:02:39 +0000 Subject: [PATCH] ContentMonster stuff --- api/urls.py | 18 +++- api/views/urls.py | 24 ++++++ core/migrations/0008_vesselalias.py | 22 +++++ core/models/course.py | 5 ++ core/models/crew.py | 18 ++++ core/models/vessel.py | 24 ++++++ core/urls/admin.py | 41 +++++++-- core/views/admin/instances.py | 0 core/views/admin/replication/__init__.py | 0 core/views/admin/replication/sources.py | 83 +++++++++++++++++++ core/views/admin/replication/targets.py | 83 +++++++++++++++++++ .../js/admin/replication_sources_datatable.js | 25 ++++++ .../js/admin/replication_targets_datatable.js | 25 ++++++ static/core/js/admin/vessels_datatable.js | 6 +- .../core/admin/replication_sources_list.html | 45 ++++++++++ .../core/admin/replication_sources_new.html | 18 ++++ .../core/admin/replication_targets_list.html | 45 ++++++++++ .../core/admin/replication_targets_new.html | 18 ++++ templates/core/sidebar.html | 4 +- 19 files changed, 490 insertions(+), 14 deletions(-) create mode 100644 core/migrations/0008_vesselalias.py create mode 100644 core/models/course.py create mode 100644 core/models/crew.py create mode 100644 core/views/admin/instances.py create mode 100644 core/views/admin/replication/__init__.py create mode 100644 core/views/admin/replication/sources.py create mode 100644 core/views/admin/replication/targets.py create mode 100644 static/core/js/admin/replication_sources_datatable.js create mode 100644 static/core/js/admin/replication_targets_datatable.js create mode 100644 templates/core/admin/replication_sources_list.html create mode 100644 templates/core/admin/replication_sources_new.html create mode 100644 templates/core/admin/replication_targets_list.html create mode 100644 templates/core/admin/replication_targets_new.html diff --git a/api/urls.py b/api/urls.py index fb01b41..7d3695b 100644 --- a/api/urls.py +++ b/api/urls.py @@ -1,13 +1,23 @@ from django.urls import path, include -from .views.urls import VesselsDataTableURLView, VesselsDeleteURLView, VesselsEditURLView, StaticsURLView +from .views.urls import VesselsDataTableURLView, VesselsDeleteURLView, VesselsEditURLView, ReplicationSourcesDataTableURLView, ReplicationSourcesDeleteURLView, ReplicationSourcesEditURLView, ReplicationTargetsDataTableURLView, ReplicationTargetsDeleteURLView, ReplicationTargetsEditURLView, StaticsURLView from .views.vessels import VesselsLocationView urlpatterns = [ - path("urls/datatable/vessels/", VesselsDataTableURLView.as_view(), name=""), - path("urls/datatable/vessels/edit//", VesselsDataTableURLView.as_view(), name=""), - path("urls/datatable/vessels/delete//", VesselsDataTableURLView.as_view(), name=""), + path("urls/vessels/datatable/", VesselsDataTableURLView.as_view(), name=""), + path("urls/vessels/edit//", VesselsEditURLView.as_view(), name=""), + path("urls/vessels/delete//", VesselsDeleteURLView.as_view(), name=""), + + path("urls/replication/targets/datatable/", ReplicationTargetsDataTableURLView.as_view(), name=""), + path("urls/replication/targets/edit//", ReplicationTargetsEditURLView.as_view(), name=""), + path("urls/replication/targets/delete//", ReplicationTargetsDeleteURLView.as_view(), name=""), + + path("urls/replication/sources/datatable/", ReplicationSourcesDataTableURLView.as_view(), name=""), + path("urls/replication/sources/edit//", ReplicationSourcesEditURLView.as_view(), name=""), + path("urls/replication/sources/delete//", ReplicationSourcesDeleteURLView.as_view(), name=""), + path("urls/static/", StaticsURLView.as_view(), name=""), + path("vessels/location//", VesselsLocationView.as_view(), name=""), ] diff --git a/api/views/urls.py b/api/views/urls.py index 85a96e4..e65ef82 100644 --- a/api/views/urls.py +++ b/api/views/urls.py @@ -17,6 +17,30 @@ class VesselsDeleteURLView(LoginRequiredMixin, View): def get(self, request, *args, **kwargs): return JsonResponse(reverse_lazy("core:admin_vessels_delete", kwargs["id"]), safe=False) +class ReplicationSourcesDataTableURLView(LoginRequiredMixin, View): + def get(self, request, *args, **kwargs): + return JsonResponse(reverse_lazy("core:admin_replication_sources_datatable"), safe=False) + +class ReplicationSourcesEditURLView(LoginRequiredMixin, View): + def get(self, request, *args, **kwargs): + return JsonResponse(reverse_lazy("core:admin_replication_sources_edit", kwargs["id"]), safe=False) + +class ReplicationSourcesDeleteURLView(LoginRequiredMixin, View): + def get(self, request, *args, **kwargs): + return JsonResponse(reverse_lazy("core:admin_replication_sources_delete", kwargs["id"]), safe=False) + +class ReplicationTargetsDataTableURLView(LoginRequiredMixin, View): + def get(self, request, *args, **kwargs): + return JsonResponse(reverse_lazy("core:admin_replication_targets_datatable"), safe=False) + +class ReplicationTargetsEditURLView(LoginRequiredMixin, View): + def get(self, request, *args, **kwargs): + return JsonResponse(reverse_lazy("core:admin_replication_targets_edit", kwargs["id"]), safe=False) + +class ReplicationTargetsDeleteURLView(LoginRequiredMixin, View): + def get(self, request, *args, **kwargs): + return JsonResponse(reverse_lazy("core:admin_replication_targets_delete", kwargs["id"]), safe=False) + class StaticsURLView(View): def get(self, request, *args, **kwargs): return JsonResponse(static(request.GET["file"]), safe=False) \ No newline at end of file diff --git a/core/migrations/0008_vesselalias.py b/core/migrations/0008_vesselalias.py new file mode 100644 index 0000000..9786efd --- /dev/null +++ b/core/migrations/0008_vesselalias.py @@ -0,0 +1,22 @@ +# Generated by Django 4.1.1 on 2022-09-20 12:11 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0007_replicationfile_replicationsource_replicationtarget_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='VesselAlias', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('alias', models.CharField(max_length=64)), + ('vessel', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.vessel')), + ], + ), + ] diff --git a/core/models/course.py b/core/models/course.py new file mode 100644 index 0000000..2d30f7d --- /dev/null +++ b/core/models/course.py @@ -0,0 +1,5 @@ +class Course(models.Model): + id = models.IntegerField(primary_key=True) + title = models.CharField(max_length=256) + shortcode = models.CharField(max_length=64) + \ No newline at end of file diff --git a/core/models/crew.py b/core/models/crew.py new file mode 100644 index 0000000..f6796fa --- /dev/null +++ b/core/models/crew.py @@ -0,0 +1,18 @@ +from django.db import models + +from .course import Course +from .vessel import Vessel + + +class CrewMember(models.Model): + pin = models.IntegerField(primary_key=True) + first_name = models.CharField(max_length=256) + last_name = models.CharField(max_length=256) + email = models.EmailField() + dob = models.DateField() + + +class CourseAssignment(models.Model): + crew = models.ForeignKey(CrewMember, models.CASCADE) + course = models.ForeignKey(Course, models.CASCADE) + vessel = models.ForeignKey(Vessel, models.CASCADE, null=True) diff --git a/core/models/vessel.py b/core/models/vessel.py index 032bdde..7073128 100644 --- a/core/models/vessel.py +++ b/core/models/vessel.py @@ -1,5 +1,7 @@ from django.db import models +from typing import List, Dict + from pycruisemapper.classes import CruiseMapper, Ship @@ -8,6 +10,23 @@ class Vessel(models.Model): imo = models.IntegerField("IMO", null=True, blank=True) mmsi = models.IntegerField("MMSI", null=True, blank=True) + def get_names(self) -> List[str]: + names = [self.name] + + for alias in self.vesselalias_set: + names.append(alias.alias) + + return names + + def name_dict(cls) -> Dict: + names = {} + + for vessel in cls.objects.all(): + for name in vessel.get_names(): + names[name] = vessel + + return names + def query_cruisemapper(self) -> Ship: cm = CruiseMapper() all_ships = cm.get_ships() @@ -31,3 +50,8 @@ class Vessel(models.Model): pass return ship + + +class VesselAlias(models.Model): + vessel = models.ForeignKey(Vessel, models.CASCADE) + alias = models.CharField(max_length=64) diff --git a/core/urls/admin.py b/core/urls/admin.py index 095dd70..dc64b5d 100644 --- a/core/urls/admin.py +++ b/core/urls/admin.py @@ -1,12 +1,43 @@ from django.urls import path from ..views.frontend import NotImplementedView -from ..views.admin.vessels import AdminVesselsListView, AdminVesselsListDataTableView, AdminVesselsCreateView +from ..views.admin.vessels import AdminVesselsListView, AdminVesselsListDataTableView, AdminVesselsCreateView, AdminVesselsUpdateView, AdminVesselsDeleteView +from ..views.admin.replication.sources import AdminReplicationSourcesListView, AdminReplicationSourcesListDataTableView, AdminReplicationSourcesCreateView, AdminReplicationSourcesUpdateView, AdminReplicationSourcesDeleteView +from ..views.admin.replication.targets import AdminReplicationTargetsListView, AdminReplicationTargetsListDataTableView, AdminReplicationTargetsCreateView, AdminReplicationTargetsUpdateView, AdminReplicationTargetsDeleteView urlpatterns = [ - path("admin/", NotImplementedView.as_view(), name="admin"), + path("", NotImplementedView.as_view(), name="admin"), + path("vessels/", AdminVesselsListView.as_view(), name="admin_vessels"), - path("vessels/new/", AdminVesselsCreateView.as_view(), name="admin_vessels_create"), - path("vessels/datatable/", AdminVesselsListDataTableView.as_view(), name="admin_vessels_datatable"), -] \ No newline at end of file + path("vessels/new/", AdminVesselsCreateView.as_view(), + name="admin_vessels_create"), + path("vessels/datatable/", AdminVesselsListDataTableView.as_view(), + name="admin_vessels_datatable"), + path("vessels//", AdminVesselsCreateView.as_view(), + name="admin_vessels_edit"), + path("vessels//delete/", AdminVesselsCreateView.as_view(), + name="admin_vessels_delete"), + + path("replication/sources/", AdminReplicationSourcesListView.as_view(), + name="admin_replication_sources"), + path("replication/sources/new/", AdminReplicationSourcesCreateView.as_view(), + name="admin_replication_sources_create"), + path("replication/sources/datatable/", AdminReplicationSourcesListDataTableView.as_view(), + name="admin_replication_sources_datatable"), + path("replication/sources//", AdminReplicationSourcesCreateView.as_view(), + name="admin_replication_sources_edit"), + path("replication/sources//delete/", AdminReplicationSourcesCreateView.as_view(), + name="admin_replication_sources_delete"), + + path("replication/targets/", AdminReplicationTargetsListView.as_view(), + name="admin_replication_targets"), + path("replication/targets/new/", AdminReplicationTargetsCreateView.as_view(), + name="admin_replication_targets_create"), + path("replication/targets/datatable/", AdminReplicationTargetsListDataTableView.as_view(), + name="admin_replication_targets_datatable"), + path("replication/targets//", AdminReplicationTargetsCreateView.as_view(), + name="admin_replication_targets_edit"), + path("replication/targets//delete/", AdminReplicationTargetsCreateView.as_view(), + name="admin_replication_targets_delete"), +] diff --git a/core/views/admin/instances.py b/core/views/admin/instances.py new file mode 100644 index 0000000..e69de29 diff --git a/core/views/admin/replication/__init__.py b/core/views/admin/replication/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/views/admin/replication/sources.py b/core/views/admin/replication/sources.py new file mode 100644 index 0000000..6f4cc9d --- /dev/null +++ b/core/views/admin/replication/sources.py @@ -0,0 +1,83 @@ +from django.views.generic import TemplateView, UpdateView, DeleteView, CreateView +from django.urls import reverse_lazy + +from ajax_datatable.views import AjaxDatatableView +from crispy_forms.helper import FormHelper +from crispy_forms.layout import Submit + +from ....models.replication import ReplicationSource +from ....mixins.frontend import TitleMixin +from ....mixins.auth import SuperuserRequiredMixin + + +class AdminReplicationSourcesListView(TitleMixin, SuperuserRequiredMixin, TemplateView): + title = "Replication Sources" + template_name = "core/admin/replication_sources_list.html" + + +class AdminReplicationSourcesListDataTableView(SuperuserRequiredMixin, AjaxDatatableView): + model = ReplicationSource + title = 'Replication Sources' + initial_order = [["name", "asc"], ] + length_menu = [[10, 20, 50, 100, -1], [10, 20, 50, 100, 'all']] + search_values_separator = '+' + + column_defs = [ + AjaxDatatableView.render_row_tools_column_def(), + {'name': 'id', 'visible': False, }, + {'name': 'name', 'visible': True, }, + {'name': 'location', 'visible': True, }, + ] + + def customize_row(self, row, obj): + row['edit'] = f""" + + Edit + + + Delete + + """ + + +class AdminReplicationSourcesCreateView(TitleMixin, SuperuserRequiredMixin, CreateView): + model = ReplicationSource + title = "Create Replication Source" + template_name = "core/admin/replication_sources_new.html" + fields = ["name", "location"] + + def get_form(self, form_class=None): + form = super().get_form(form_class) + form.helper = FormHelper() + form.helper.add_input(Submit('submit', 'Create', css_class='btn-primary')) + return form + + def get_success_url(self): + return reverse_lazy("core:admin_replication_sources") + + +class AdminReplicationSourcesUpdateView(TitleMixin, SuperuserRequiredMixin, UpdateView): + model = ReplicationSource + title = "Edit Replication Source" + template_name = "core/admin/replication_sources_edit.html" + fields = ["name", "location"] + + def get_form(self, form_class=None): + form = super().get_form(form_class) + form.helper = FormHelper() + form.helper.add_input(Submit('submit', 'Edit', css_class='btn-primary')) + return form + + def get_success_url(self): + return reverse_lazy("core:admin_replication_sources") + + +class AdminReplicationSourcesDeleteView(TitleMixin, SuperuserRequiredMixin, DeleteView): + model = ReplicationSource + title = "Delete Replication Source" + template_name = "core/admin/replication_sources_delete.html" + + def get_success_url(self): + return reverse_lazy("core:admin_replication_sources") \ No newline at end of file diff --git a/core/views/admin/replication/targets.py b/core/views/admin/replication/targets.py new file mode 100644 index 0000000..49780f1 --- /dev/null +++ b/core/views/admin/replication/targets.py @@ -0,0 +1,83 @@ +from django.views.generic import TemplateView, UpdateView, DeleteView, CreateView +from django.urls import reverse_lazy + +from ajax_datatable.views import AjaxDatatableView +from crispy_forms.helper import FormHelper +from crispy_forms.layout import Submit + +from ....models.replication import ReplicationTarget +from ....mixins.frontend import TitleMixin +from ....mixins.auth import SuperuserRequiredMixin + + +class AdminReplicationTargetsListView(TitleMixin, SuperuserRequiredMixin, TemplateView): + title = "Replication Targets" + template_name = "core/admin/replication_targets_list.html" + + +class AdminReplicationTargetsListDataTableView(SuperuserRequiredMixin, AjaxDatatableView): + model = ReplicationTarget + title = 'Replication Targets' + initial_order = [["name", "asc"], ] + length_menu = [[10, 20, 50, 100, -1], [10, 20, 50, 100, 'all']] + search_values_separator = '+' + + column_defs = [ + AjaxDatatableView.render_row_tools_column_def(), + {'name': 'id', 'visible': False, }, + {'name': 'name', 'visible': True, }, + {'name': 'address', 'visible': True, }, + ] + + def customize_row(self, row, obj): + row['edit'] = f""" + + Edit + + + Delete + + """ + + +class AdminReplicationTargetsCreateView(TitleMixin, SuperuserRequiredMixin, CreateView): + model = ReplicationTarget + title = "Create Replication Target" + template_name = "core/admin/replication_targets_new.html" + fields = ["name", "address", "username"] + + def get_form(self, form_class=None): + form = super().get_form(form_class) + form.helper = FormHelper() + form.helper.add_input(Submit('submit', 'Create', css_class='btn-primary')) + return form + + def get_success_url(self): + return reverse_lazy("core:admin_replication_targets") + + +class AdminReplicationTargetsUpdateView(TitleMixin, SuperuserRequiredMixin, UpdateView): + model = ReplicationTarget + title = "Edit Replication Target" + template_name = "core/admin/replication_targets_edit.html" + fields = ["name", "directory", "username"] + + def get_form(self, form_class=None): + form = super().get_form(form_class) + form.helper = FormHelper() + form.helper.add_input(Submit('submit', 'Edit', css_class='btn-primary')) + return form + + def get_success_url(self): + return reverse_lazy("core:admin_replication_targets") + + +class AdminReplicationTargetsDeleteView(TitleMixin, SuperuserRequiredMixin, DeleteView): + model = ReplicationTarget + title = "Delete Replication Target" + template_name = "core/admin/replication_targets_delete.html" + + def get_success_url(self): + return reverse_lazy("core:admin_replication_targets") \ No newline at end of file diff --git a/static/core/js/admin/replication_sources_datatable.js b/static/core/js/admin/replication_sources_datatable.js new file mode 100644 index 0000000..8331964 --- /dev/null +++ b/static/core/js/admin/replication_sources_datatable.js @@ -0,0 +1,25 @@ +$(document).ready(function () { + $.getJSON("/api/urls/replication/sources/datatable/") + .done(function (data) { + AjaxDatatableViewUtils.initialize_table( + $('#datatable_replication_sources'), + data, + ); + }); +}); + +function deleteReplicationSource(row) { + id = row.closest('tr').id.substr(4); + $.getJSON("/api/urls/replication/sources/delete/" + id + "/") + .done(function (data) { + window.location.href = data; + }); +} + +function editReplicationSource(row) { + id = row.closest('tr').id.substr(4); + $.getJSON("/api/urls/replication/sources/edit/" + id + "/") + .done(function (data) { + window.location.href = data; + }); +} \ No newline at end of file diff --git a/static/core/js/admin/replication_targets_datatable.js b/static/core/js/admin/replication_targets_datatable.js new file mode 100644 index 0000000..bcf33f2 --- /dev/null +++ b/static/core/js/admin/replication_targets_datatable.js @@ -0,0 +1,25 @@ +$(document).ready(function () { + $.getJSON("/api/urls/replication/targets/datatable/") + .done(function (data) { + AjaxDatatableViewUtils.initialize_table( + $('#datatable_replication_targets'), + data, + ); + }); +}); + +function deleteReplicationTarget(row) { + id = row.closest('tr').id.substr(4); + $.getJSON("/api/urls/replication/targets/delete/" + id + "/") + .done(function (data) { + window.location.href = data; + }); +} + +function editReplicationTarget(row) { + id = row.closest('tr').id.substr(4); + $.getJSON("/api/urls/replication/targets/edit/" + id + "/") + .done(function (data) { + window.location.href = data; + }); +} \ No newline at end of file diff --git a/static/core/js/admin/vessels_datatable.js b/static/core/js/admin/vessels_datatable.js index 657679f..fcd27b1 100644 --- a/static/core/js/admin/vessels_datatable.js +++ b/static/core/js/admin/vessels_datatable.js @@ -1,5 +1,5 @@ $(document).ready(function () { - $.getJSON("/api/urls/datatable/vessels/") + $.getJSON("/api/urls/vessels/datatable/") .done(function (data) { AjaxDatatableViewUtils.initialize_table( $('#datatable_vessels'), @@ -10,7 +10,7 @@ $(document).ready(function () { function deleteVessel(row) { id = row.closest('tr').id.substr(4); - $.getJSON("/api/urls/datatable/vessels/delete/" + id + "/") + $.getJSON("/api/urls/vessels/delete/" + id + "/") .done(function (data) { window.location.href = data; }); @@ -18,7 +18,7 @@ function deleteVessel(row) { function editVessel(row) { id = row.closest('tr').id.substr(4); - $.getJSON("/api/urls/datatable/vessels/edit/" + id + "/") + $.getJSON("/api/urls/vessels/edit/" + id + "/") .done(function (data) { window.location.href = data; }); diff --git a/templates/core/admin/replication_sources_list.html b/templates/core/admin/replication_sources_list.html new file mode 100644 index 0000000..803b067 --- /dev/null +++ b/templates/core/admin/replication_sources_list.html @@ -0,0 +1,45 @@ +{% extends "core/base.html"%} +{% load static %} + +{% block styles %} + + + +{% endblock %} + +{% block content %} +
+
+

List of Replication Sources

+ +
+
+
+ +
+
+
+
+{% endblock %} + +{% block scripts %} + + + + + + + + + + + + + +{% endblock %} \ No newline at end of file diff --git a/templates/core/admin/replication_sources_new.html b/templates/core/admin/replication_sources_new.html new file mode 100644 index 0000000..dffb5c9 --- /dev/null +++ b/templates/core/admin/replication_sources_new.html @@ -0,0 +1,18 @@ +{% extends "core/base.html"%} +{% load crispy_forms_tags %} + +{% block content %} +
+
+

Create New Replication Source

+
+ +
+
+
+ {% crispy form %} +
+
+{% endblock %} diff --git a/templates/core/admin/replication_targets_list.html b/templates/core/admin/replication_targets_list.html new file mode 100644 index 0000000..093cc79 --- /dev/null +++ b/templates/core/admin/replication_targets_list.html @@ -0,0 +1,45 @@ +{% extends "core/base.html"%} +{% load static %} + +{% block styles %} + + + +{% endblock %} + +{% block content %} +
+
+

List of Replication Targets

+ +
+
+
+ +
+
+
+
+{% endblock %} + +{% block scripts %} + + + + + + + + + + + + + +{% endblock %} \ No newline at end of file diff --git a/templates/core/admin/replication_targets_new.html b/templates/core/admin/replication_targets_new.html new file mode 100644 index 0000000..676d3b5 --- /dev/null +++ b/templates/core/admin/replication_targets_new.html @@ -0,0 +1,18 @@ +{% extends "core/base.html"%} +{% load crispy_forms_tags %} + +{% block content %} +
+
+

Create New Replication Target

+
+ +
+
+
+ {% crispy form %} +
+
+{% endblock %} diff --git a/templates/core/sidebar.html b/templates/core/sidebar.html index d442a13..67a834f 100644 --- a/templates/core/sidebar.html +++ b/templates/core/sidebar.html @@ -132,7 +132,7 @@