Compare commits

..

No commits in common. "bf4817ac5d7859ace3614e97c655db042076b239" and "0b285b068caa7a46ff8ccbc887b14f69da716e1c" have entirely different histories.

12 changed files with 109 additions and 1666 deletions

View File

@ -11,5 +11,5 @@ router.register(r'products', GtinProductViewSet)
urlpatterns = [ urlpatterns = [
path('', include(router.urls)), path('', include(router.urls)),
path('auth/', include('rest_framework.urls', namespace='rest_framework')) path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
] ]

View File

@ -1,9 +1,6 @@
from rest_framework import viewsets, status from django.shortcuts import render
from rest_framework import viewsets
from rest_framework import permissions from rest_framework import permissions
from rest_framework.decorators import action
from rest_framework.response import Response
import asset.gtin_service
from api.serializers import ContainerSerializer, ContainerTypeSerializer, AssetSerializer, GtinProductSerializer from api.serializers import ContainerSerializer, ContainerTypeSerializer, AssetSerializer, GtinProductSerializer
from container.models import Container, ContainerType from container.models import Container, ContainerType
from asset.models import Asset, GtinProduct from asset.models import Asset, GtinProduct
@ -39,6 +36,7 @@ class AssetViewSet(viewsets.ModelViewSet):
filterset_fields = ['named_id', 'quantity'] filterset_fields = ['named_id', 'quantity']
class GtinProductViewSet(viewsets.ModelViewSet): class GtinProductViewSet(viewsets.ModelViewSet):
""" """
API endpoint that allows containers to be viewed or edited. API endpoint that allows containers to be viewed or edited.
@ -48,25 +46,3 @@ class GtinProductViewSet(viewsets.ModelViewSet):
permission_classes = [permissions.IsAuthenticated] permission_classes = [permissions.IsAuthenticated]
filterset_fields = ['gtin'] filterset_fields = ['gtin']
def retrieve(self, request, pk=None):
if pk:
item = GtinProduct.objects.get(id=pk)
serializer = GtinProductSerializer(item)
return Response({"status": "success", "data": serializer.data}, status=status.HTTP_200_OK)
items = GtinProduct.objects.all()
serializer = GtinProductSerializer(items, many=True)
return Response({"status": "success", "data": serializer.data}, status=status.HTTP_200_OK)
@action(detail=True, methods=['GET'])
def by_gtin(self, request, gtin=None):
if gtin:
item = asset.gtin_service.get_by_gtin(gtin=gtin)
if item:
serializer = GtinProductSerializer(item)
return Response({"status": "success", "data": serializer.data}, status=status.HTTP_200_OK)
return Response(
{"status": "failed", "reason": "Could not find a product for given GTIN", "gtin": gtin},
status=status.HTTP_404_NOT_FOUND)
return Response({"status": "failed", "reason": "No GTIN given, please provide a valid GTIN"},
status=status.HTTP_400_BAD_REQUEST)

View File

@ -1,226 +0,0 @@
{% extends "base.html" %}
{% load static %}
{% block additional_css %}
<link rel="preload" as="style" onload="this.rel='stylesheet';this.onload=null" href="https://unpkg.com/normalize.css@8.0.0/normalize.css">
<link rel="preload" as="style" onload="this.rel='stylesheet';this.onload=null" href="https://unpkg.com/milligram@1.3.0/dist/milligram.min.css">
{% endblock %}
{% block title %}Smartphone Scanner{% endblock %}
{% block content %}
<div class="container" >
<div class="row-mb8" id="video-button-content">
<a class="button" id="startButton">Start</a>
<a class="button-outline" id="resetButton">Reset</a>
</div>
<div class="row" id="video-content">
<div class="col-6">
<video id="video" width="450" height="320" style="border: 1px solid gray"></video>
</div>
<div class="col-2" id="sourceSelectPanel" style="display:none">
<label for="sourceSelect">Change video source:</label>
<select id="sourceSelect" style="max-width:400px">
</select>
</div>
<div class="col-2">
<label>Result:</label>
<pre><code id="result"></code></pre>
<ul id="barcode-list"></ul>
</div>
</div>
</div>
<script type="text/javascript">
function beep() {
var audio = new Audio("{% static 'sound/beep.mp3' %}");
audio.volume = 0.1
console.log("Audio play {% static 'sound/beep.mp3' %}")
audio.play();
}
// check compatibility
if (!('BarcodeDetector' in window)) {
console.log('Barcode Detector is not supported by this browser.');
} else {
console.log('Barcode Detector supported!');
// create new detector
// var barcodeDetector = new BarcodeDetector({formats: ['code_128', 'code_39', 'code_93', 'codabar', 'data_matrix', 'ean_13', 'ean_8', 'qr_code', 'upc_a', 'upc_e']});
var barcodeDetector = new BarcodeDetector({formats: ['code_128', 'ean_13']});
console.log('Supported code formats:');
BarcodeDetector.getSupportedFormats().then(supportedFormats => {
supportedFormats.forEach(format => console.log(format));
});
console.log('end-of-format-list');
}
async function detect() {
const mediaStream = await navigator.mediaDevices.getUserMedia({
video: {facingMode: 'environment'}
});
const video = document.getElementById('video');
// const video = document.createElement('video');
let itemsFound = [];
video.srcObject = mediaStream;
video.autoplay = true;
const list = document.getElementById('barcode-list');
// list.before(video);
function render() {
barcodeDetector
.detect(video)
.then(barcodes => {
barcodes.forEach(barcode => {
if (!itemsFound.includes(barcode.rawValue)) {
itemsFound.push(barcode.rawValue);
const li = document.createElement('li');
li.innerHTML = barcode.rawValue;
list.appendChild(li);
console.log('Got scan ' + barcode.rawValue);
}
});
// beep();
})
.catch(console.error);
}
(function renderLoop() {
requestAnimationFrame(renderLoop);
render();
})();
}
window.addEventListener('load', function () {
detect();
document.getElementById('resetButton').addEventListener('click', () => {
document.getElementById('result').textContent = '';
codeReader.reset();
console.log('Reset.')
});
});
</script>
<hr />
<div class="row mb-3">
<div class="col-8">
<div class="input-group">
<input class="form-control" type="text" maxlength="40" id="container_id" placeholder="Container ID">
<input class="form-control" type="text" maxlength="40" id="asset_id" placeholder="Asset ID">
</div>
</div>
<div class="col-2">
<div class="input-group">
<input class="btn btn-primary" id="book-in-button" type="button" value="+Book">
<input class="btn btn-primary" id="book-out-button" type="button" value="-Book">
</div>
</div>
<div class="col-8">
<div class="input-group">
<textarea class="form-control" readonly="readonly" rows="4" id="container_details"></textarea>
<textarea class="form-control" readonly="readonly" rows="4" id="asset_details"></textarea>
</div>
</div>
</div>
<div class="row">
<div class="input-group">
<textarea class="form-control mb-2" id="chat-log" cols="100" rows="10"></textarea>
<input class="btn btn-secondary" id="clear-chat-area" type="button" value="Clear">
</div>
</div>
<script>
var containerIsValid = false;
var assetIsValid = false;
async function getContainerInfo(containerId) {
document.querySelector('#container_id').value = containerId;
url = '/api/containers?named_id=' + containerId;
document.querySelector('#container_details').value = 'Trying ' + url;
const response = await fetch(url);
const container = await response.json();
if (container.count >= 1) {
document.querySelector('#container_details').value = container.results[0].description;
containerIsValid = true;
} else {
document.querySelector('#container_details').value = document.querySelector('#container_details').value + "\nERROR: No result\n";
console.log(response);
containerIsValid = false;
}
}
async function getAssetInfo(assetId) {
document.querySelector('#asset_id').value = assetId;
url = '/api/assets?named_id=' + assetId;
document.querySelector('#asset_details').value = 'Trying ' + url;
const response = await fetch(url);
const asset = await response.json();
if (asset.count >= 1) {
document.querySelector('#asset_details').value = asset.results[0].description;
assetIsValid = true;
} else {
document.querySelector('#asset_details').value = document.querySelector('#asset_details').value + "\nERROR: No result\n";
console.log(response);
assetIsValid = false;
}
}
function useScannedText(msg) {
// const data = JSON.parse(e.data);
// msg = String(data.message);
document.querySelector('#chat-log').value += (msg + '\n');
if (msg.startsWith('C-')) {
getContainerInfo(data.message);
// document.querySelector('#container_id').value = msg;
} else if (msg.startsWith('A-')) {
getAssetInfo(data.message);
// document.querySelector('#asset_id').value = msg;
} else {
assetId = 'A-' + msg;
document.querySelector('#asset_id').value = assetId;
getAssetInfo(assetId);
}
};
document.querySelector('#clear-chat-area').onclick = function(e) {
document.querySelector('#chat-log').value = "cleared\n";
}
document.querySelector('#book-in-button').onclick = function(e) {
if (!containerIsValid) {
msg = 'Cannot book-in as container is invalid';
console.log(msg);
document.querySelector('#chat-log').value += ('ERROR: ' + msg + '\n');
return;
}
if (!assetIsValid) {
msg = 'Cannot book-in as asset is invalid';
console.log(msg);
document.querySelector('#chat-log').value += ('ERROR: ' + msg + '\n');
return;
}
}
document.querySelector('#book-out-button').onclick = function(e) {
if (!containerIsValid) {
msg = 'Cannot book-out as container is invalid';
console.log(msg);
document.querySelector('#chat-log').value += ('ERROR: ' + msg + '\n');
return;
}
if (!assetIsValid) {
msg = 'Cannot book-out as asset is invalid';
console.log(msg);
document.querySelector('#chat-log').value += ('ERROR: ' + msg + '\n');
return;
}
}
</script>
{% endblock %}

View File

@ -56,8 +56,7 @@
</div> </div>
<div class="row"> <div class="row">
<h1>Use your smartphone</h1> <h1>Use your smartphone</h1>
<p>Use your <a href="{% url 'booker:smartphone_scanner' %}">smartphone</a> to scan.</p> <p>Use your <a class="navbar-brand" href="{% url 'booker:smartphone_scanner' %}">smartphone</a> to scan.</p>
<p>Use your <a href="{% url 'booker:chrome_scanner' %}">chrome Barcode-Scanner to scan.</p>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -2,223 +2,118 @@
{% load static %} {% load static %}
{% block additional_css %} {% block additional_css %}
<link rel="preload" as="style" onload="this.rel='stylesheet';this.onload=null" href="https://unpkg.com/normalize.css@8.0.0/normalize.css">
<link rel="preload" as="style" onload="this.rel='stylesheet';this.onload=null" href="https://unpkg.com/milligram@1.3.0/dist/milligram.min.css">
{% endblock %} {% endblock %}
{% block title %}Smartphone Scanner{% endblock %} {% block title %}Smartphone Scanner{% endblock %}
{% block content %} {% block content %}
<style>
#interactive canvas { position: absolute; left: 0; }
</style>
<div class="container" > <div class="container" >
<div class="row" id="video-button-content">
<div class="col-1"> <div class="row-mb8" id="video-button-content">
<a class="btn btn-primary" id="startButton">Start</a> <a class="button" id="startButton">Start</a>
</div> <a class="button-outline" id="resetButton">Reset</a>
<div class="col-1">
<a class="btn btn-outline-primary" id="resetButton">Reset</a>
</div>
<div class="col-1">
<a class="btn btn-outline-primary" id="clearOverlayButton">Clear</a>
</div>
</div> </div>
<div class="row" id="video-content"> <div class="row" id="video-content">
<div id="interactive" class="viewport col-12" style="position: relative;"> <div class="col-6">
<!-- QuaggaJS will populate this element --> <video id="video" width="450" height="320" style="border: 1px solid gray"></video>
</div> </div>
<!--
<div class="col-8"> <div class="col-2" id="sourceSelectPanel" style="display:none">
<video id="video" autoplay="true" width="640" height="480" style="border: 1px solid gray"></video>
</div>-->
</div>
<div class="row" id="control-content">
<div class="col-6" id="sourceSelectPanel" style="display:none">
<div>
<label for="sourceSelect">Change video source:</label> <label for="sourceSelect">Change video source:</label>
<select id="sourceSelect" style="max-width:400px"></select> <select id="sourceSelect" style="max-width:400px">
</select>
</div> </div>
</div>
<div class="col-6" id="scan-result-panel" style="display:none"> <div class="col-2">
<div> <label>Result:</label>
<label>Scan:</label>
<pre><code id="result"></code></pre> <pre><code id="result"></code></pre>
</div> </div>
</div> </div>
</div>
</div> </div>
<script type="text/javascript" src="https://unpkg.com/@zxing/library@latest"></script>
<script type="text/javascript" src="{% static 'quagga/dist/quagga.js' %}"></script>
<script type="text/javascript"> <script type="text/javascript">
function beep() { function beep() {
var audio = new Audio("{% static 'sound/beep.mp3' %}"); var audio = new Audio("{% static 'sound/beep.mp3' %}");
audio.volume = 0.02; audio.volume = 0.1
console.log("Audio play {% static 'sound/beep.mp3' %}"); console.log("Audio play {% static 'sound/beep.mp3' %}")
audio.play(); audio.play();
} }
function clearCanvas() {
canvas = document.querySelector('#interactive .drawingBuffer');
drawing = (canvas != null) ? canvas.getContext('2d') : null;
console.log('Clearing canvas, drawing=' + drawing + ', canvas=' + canvas);
if (drawing != null) {
drawing.clearRect(0, 0, canvas.width, canvas.height);
console.log('Clearing done');
}
}
console.log('detected HW concurrency: ' + self.navigator.hardwareConcurrency);
window.addEventListener('load', function () { window.addEventListener('load', function () {
let selectedDeviceId; let selectedDeviceId;
let lastScanResult = ''; let lastScanResult = '';
let config = { // const codeReader = new ZXing.BrowserBarcodeReader()
inputStream: { const codeReader = new ZXing.BrowserMultiFormatReader()
name: "Live", console.log('ZXing code reader initialized')
type: "LiveStream", codeReader.getVideoInputDevices()
constraints: { .then((videoInputDevices) => {
facingMode: "environment", const sourceSelect = document.getElementById('sourceSelect')
}, selectedDeviceId = videoInputDevices[0].deviceId
if (videoInputDevices.length > 1) {
videoInputDevices.forEach((element) => {
const sourceOption = document.createElement('option')
sourceOption.text = element.label
sourceOption.value = element.deviceId
sourceSelect.appendChild(sourceOption)
})
target: document.getElementById('interactive'),
/*area: {
top: '0%',
bottom: '0%',
left: '0%',
right: '0%'
},*/
},
//numOfWorkers: 4,
locate: true,
debug: true,
frequency: 20,
decoder: {
readers: ["code_128_reader"],
debug: {
drawScanline: false,
drawBoundingBox: false,
showPattern: false,
showFrequency: false
},
multiple: false
},
locator: {
halfSample: false,
patchSize: "x-large", // x-small, small, medium, large, x-large
debug: {
/*showCanvas: true,*/
showPatches: false,
showFoundPatches: false,
showSkeleton: false,
showLabels: false,
showPatchLabels: false,
showRemainingPatchLabels: false,
boxFromPatches: {
showTransformed: false,
showTransformedBox: false,
showBB: true
}
}
}
};
function quagga_init() {
Quagga.init(config, function(err) {
if (err) {
console.log(err);
return;
}
console.log("Initialization finished. Ready to start");
Quagga.start();
Quagga.onDetected(function(data) {
code = data.codeResult.code;
console.log('Got scan: ' + code);
if (code && lastScanResult !== code) {
lastScanResult = code;
console.log('Got scan (cont.): ' + lastScanResult);
document.querySelector('#result').textContent = lastScanResult;
// document.getElementById('result').textContent = lastScanResult
beep();
useScannedText(lastScanResult);
console.log(data);
canvas = document.querySelector('#interactive .drawingBuffer');
drawing = canvas.getContext('2d');
drawing.clearRect(0, 0, canvas.width, canvas.height);
drawing.beginPath();
drawing.moveTo(data.line[0].x, data.line[0].y);
drawing.lineTo(data.line[1].x, data.line[1].y);
drawing.lineWidth = 2;
drawing.strokeStyle = 'yellow';
drawing.closePath();
drawing.stroke();
setTimeout(clearCanvas, 3000);
} else if (code) {
console.log('... scan again');
}
});
/*
Quagga.onProcessed(function(data) {
canvas = document.querySelector('#interactive .drawingBuffer');
if (canvas != null) {
context = canvas.getContext('2d');
if (context) {
context.clearRect(0, 0, canvas.width, canvas.height);
}
}
});*/
});
}
quagga_init();
if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {
console.log("enumerateDevices() not supported.");
return;
}
Quagga.CameraAccess.enumerateVideoDevices()
.then(function(devices) {
const sourceSelect = document.getElementById('sourceSelect');
selectedDeviceId = devices[0].deviceId; // default
if (devices.length > 1) {
devices.forEach(function(device) {
console.log(device.kind + ": " + device.label + " id=" + device.deviceId);
const sourceOption = document.createElement('option');
sourceOption.text = device.label;
sourceOption.value = device.deviceId;
sourceSelect.appendChild(sourceOption);
});
sourceSelect.onchange = () => { sourceSelect.onchange = () => {
selectedDeviceId = sourceSelect.value; selectedDeviceId = sourceSelect.value;
config.inputStream.constraints.deviceId = selectedDeviceId;
Quagga.stop();
quagga_init();
} }
const sourceSelectPanel = document.getElementById('sourceSelectPanel');
sourceSelectPanel.style.display = 'block'; const sourceSelectPanel = document.getElementById('sourceSelectPanel')
sourceSelectPanel.style.display = 'block'
} }
document.getElementById('startButton').addEventListener('click', () => { document.getElementById('startButton').addEventListener('click', () => {
beep(); beep()
Quagga.start(); codeReader.decodeFromInputVideoDeviceContinuously(selectedDeviceId, 'video', (result) => {
console.log(`Started scan from camera with id ${selectedDeviceId}`) if (result && lastScanResult !== result.text) {
lastScanResult = result.text
console.log('Got scan (cont.): ' + result)
document.getElementById('result').textContent = result.text
beep()
useScannedText(result.text)
} else if (result) {
console.log('... scan again')
}
});
/*
codeReader.decodeOnceFromVideoDevice(selectedDeviceId, 'video').then((result) => {
if (lastScanResult !== result.text) {
lastScanResult = result.text
console.log('Got scan: ' + result.text)
document.getElementById('result').textContent = result.text
useScannedText(result.text)
} else {
console.log('... scan again')
}
}).catch((err) => {
console.error(err)
document.getElementById('result').textContent = err
})
*/
console.log(`Started continous decode from camera with id ${selectedDeviceId}`)
}) })
document.getElementById('resetButton').addEventListener('click', () => { document.getElementById('resetButton').addEventListener('click', () => {
document.getElementById('result').textContent = ''; document.getElementById('result').textContent = '';
Quagga.stop(); codeReader.reset();
console.log('Reset/stopped.') console.log('Reset.')
}) })
document.getElementById('clearOverlayButton').addEventListener('click', () => { })
clearCanvas(); .catch((err) => {
console.error(err)
}) })
}) })
.catch(function(err) {
console.log(err);
});
});
</script> </script>
<hr /> <hr />
<div class="row mb-3"> <div class="row mb-3">
<div class="col-8"> <div class="col-8">
@ -250,22 +145,14 @@
var containerIsValid = false; var containerIsValid = false;
var assetIsValid = false; var assetIsValid = false;
async function getObjectInfo(url) {
const response = await fetch(url);
const object_json = response.json();
return object_json;
}
async function getContainerInfo(containerId) { async function getContainerInfo(containerId) {
document.querySelector('#container_id').value = containerId; document.querySelector('#container_id').value = containerId;
url = '/api/containers?named_id=' + containerId; url = '/api/containers?named_id=' + containerId;
document.querySelector('#container_details').value = 'Trying ' + url; document.querySelector('#container_details').value = 'Trying ' + url;
const container = await getObjectInfo(url); const response = await fetch(url);
const container = await response.json();
if (container.count >= 1) { if (container.count >= 1) {
c = container.results[0]; document.querySelector('#container_details').value = container.results[0].description;
console.log(c);
containerType = await getObjectInfo(c.container_type);
document.querySelector('#container_details').value = c.description + "\n" + c.named_id + ': ' + c.color + "\n" + containerType.description;
containerIsValid = true; containerIsValid = true;
} else { } else {
document.querySelector('#container_details').value = document.querySelector('#container_details').value + "\nERROR: No result\n"; document.querySelector('#container_details').value = document.querySelector('#container_details').value + "\nERROR: No result\n";
@ -291,11 +178,15 @@
} }
function useScannedText(msg) { function useScannedText(msg) {
// const data = JSON.parse(e.data);
// msg = String(data.message);
document.querySelector('#chat-log').value += (msg + '\n'); document.querySelector('#chat-log').value += (msg + '\n');
if (msg.startsWith('C-')) { if (msg.startsWith('C-')) {
getContainerInfo(msg); getContainerInfo(data.message);
// document.querySelector('#container_id').value = msg;
} else if (msg.startsWith('A-')) { } else if (msg.startsWith('A-')) {
getAssetInfo(msg); getAssetInfo(data.message);
// document.querySelector('#asset_id').value = msg;
} else { } else {
assetId = 'A-' + msg; assetId = 'A-' + msg;
document.querySelector('#asset_id').value = assetId; document.querySelector('#asset_id').value = assetId;

View File

@ -6,7 +6,5 @@ app_name = 'booker'
urlpatterns = [ urlpatterns = [
path('', views.IndexView.as_view(), name='index'), path('', views.IndexView.as_view(), name='index'),
path('smartphone_scanner/', views.SmartphoneScannerView.as_view(), name='smartphone_scanner'), path('smartphone_scanner/', views.SmartphoneScannerView.as_view(), name='smartphone_scanner'),
path('chrome_scanner/', views.ChromeScannerView.as_view(), name='chrome_scanner'), path('<str:scanner_id>/', views.scanner, name='scanner')
path('<str:scanner_id>/', views.scanner_view, name='scanner'),
path('webscanner/<str:scanner_id>/', views.web_scanner_view, name='web_scanner'),
] ]

View File

@ -1,18 +1,6 @@
from datetime import datetime
from channels.layers import get_channel_layer
from django.shortcuts import render from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import ListView, TemplateView from django.views.generic import ListView, TemplateView
from gmqtt import Client
from rest_framework.utils import json
from homelog import settings
from homelog.system_user import get_system_user
from .models import Scanner from .models import Scanner
from django.http import HttpResponse
import logging
LOGGER = logging.getLogger(__name__)
class IndexView(ListView): class IndexView(ListView):
@ -20,53 +8,10 @@ class IndexView(ListView):
template_name = 'booker/index.html' template_name = 'booker/index.html'
def scanner_view(request, scanner_id): def scanner(request, scanner_id):
return render(request, 'booker/scanner.html', { return render(request, 'booker/scanner.html', {
'scanner_id': scanner_id 'scanner_id': scanner_id
}) })
class SmartphoneScannerView(TemplateView): class SmartphoneScannerView(TemplateView):
template_name = 'booker/smartphone_scanner.html' template_name = 'booker/smartphone_scanner.html'
class ChromeScannerView(TemplateView):
template_name = 'booker/chrome_scanner.html'
@csrf_exempt
def web_scanner_view(request, scanner_id):
def get_or_create_scanner(named_id):
scanner, created = Scanner.objects.get_or_create(named_id=named_id, defaults={
# 'lwt_topic': topic,
'description': 'WebAPI scanner',
'last_online_ts': datetime.now(),
'created_by': get_system_user(),
'changed_by': get_system_user()
})
if created:
LOGGER.debug(f"Created new scanner entry for {named_id}")
else:
LOGGER.debug(f"Updated scanner entry for {named_id}")
return scanner
print(f"Got {request.POST['scan']} from scanner {scanner_id}")
get_or_create_scanner(scanner_id)
topic = f"barcodescanner/{scanner_id}/scan"
'''
client = Client('homelog-webscanner')
client.set_auth_credentials(username=settings.MQTT_USER, password=settings.MQTT_PASSWORD)
client.connect(settings.MQTT_HOST, 1883, keepalive=60, version=settings.MQTT_VERSION)
client.publish(topic, request.POST['scan'])
client.disconnect()
# MqttConsumer().mqtt_publish({'topic': topic, 'payload': request.POST['scan'], 'retain': False})
'''
channel_layer = get_channel_layer()
channel_layer.group_send(
'mqtt', # scanner_id,
{"type": "distribute", "text": json.dumps({'message': request.POST['scan'], 'topic': topic})}
)
'''
'''
return HttpResponse(f"<html><body><p>OK, got {request.POST['scan']} from {scanner_id}</p></body></html>")

View File

@ -26,7 +26,7 @@ SECRET_KEY = 'django-insecure-!&87^_vnfn^am1f!w7-a)rrxcx(&5i7)h=bcl4)$8882c2-$na
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True DEBUG = True
ALLOWED_HOSTS = ['192.168.89.45', '127.0.0.1', 'localhost'] ALLOWED_HOSTS = []
# Application definition # Application definition
@ -38,7 +38,6 @@ INSTALLED_APPS = [
'booker', 'booker',
'api', 'api',
'rest_framework', 'rest_framework',
'django_filters',
'django.contrib.admin', 'django.contrib.admin',
'django.contrib.auth', 'django.contrib.auth',
'django.contrib.contenttypes', 'django.contrib.contenttypes',
@ -187,6 +186,5 @@ REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [ 'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer', 'rest_framework.renderers.BrowsableAPIRenderer',
], ]
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend']
} }

View File

@ -1,6 +1,6 @@
{% load static i18n %}<!DOCTYPE html> {% load static i18n %}<!DOCTYPE html>
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
<html lang="{{ LANGUAGE_CODE }}" xmlns="http://www.w3.org/1999/html"> <html lang="{{ LANGUAGE_CODE }}">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge"> <meta http-equiv="x-ua-compatible" content="ie=edge">
@ -13,7 +13,7 @@
{% block css %} {% block css %}
<!-- Latest compiled and minified Bootstrap CSS --> <!-- Latest compiled and minified Bootstrap CSS -->
<link rel="stylesheet" href="{% static 'bootstrap/dist/css/bootstrap.min.css' %}" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/css/bootstrap.min.css" integrity="sha512-GQGU0fMMi238uA+a/bdWJfpUGKUkBdgfFdgBm72SUQ6BeyWjoY/ton0tEjH+OSH9iP4Dfh+7HM0I9f5eR0L/4w==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<!-- Your stuff: Third-party CSS libraries go here --> <!-- Your stuff: Third-party CSS libraries go here -->
<!-- This file stores project-specific CSS --> <!-- This file stores project-specific CSS -->
@ -26,7 +26,7 @@
{# Placed at the top of the document so pages load faster with defer #} {# Placed at the top of the document so pages load faster with defer #}
{% block javascript %} {% block javascript %}
<!-- Bootstrap JS --> <!-- Bootstrap JS -->
<script defer src="{% static 'bootstrap/dist/js/bootstrap.min.js' %}" ></script> <script defer src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/js/bootstrap.min.js" integrity="sha512-OvBgP9A2JBgiRad/mM36mkzXSXaJE9BEIENnVEmeZdITvwT09xnxLtT4twkCa8m/loMbPHsvPl0T8lRGVBwjlQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- Your stuff: Third-party javascript libraries go here --> <!-- Your stuff: Third-party javascript libraries go here -->
<!-- place project specific Javascript in this file --> <!-- place project specific Javascript in this file -->

1092
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +0,0 @@
{
"name": "homelog",
"version": "1.0.0",
"description": "Home Logistics -- manage assets and containers and their locations",
"main": "index.js",
"directories": {
"doc": "doc"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Dirk Jahnke",
"license": "ISC",
"dependencies": {
"bootstrap": "^5.1.3",
"quagga": "^0.12.1"
}
}

View File

@ -1,28 +0,0 @@
asgiref==3.5.2
attrs==21.4.0
autobahn==22.4.2
Automat==20.2.0
cffi==1.15.0
channels==3.0.4
constantly==15.1.0
cryptography==37.0.2
daphne==3.0.2
Django==4.0.4
django-filter==21.1
django-npm==1.0.0
djangorestframework==3.13.1
hyperlink==21.0.0
idna==3.3
incremental==21.3.0
pyasn1==0.4.8
pyasn1-modules==0.2.8
pycparser==2.21
pyOpenSSL==22.0.0
pytz==2022.1
service-identity==21.1.0
six==1.16.0
sqlparse==0.4.2
Twisted==22.4.0
txaio==22.2.1
typing_extensions==4.2.0
zope.interface==5.4.0