mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
first attempt with adding and downloading message attachments
This commit is contained in:
parent
463a1766f1
commit
8d62550775
9 changed files with 206 additions and 121 deletions
|
@ -2,13 +2,13 @@
|
||||||
<div class="row justify-content-start mb-2">
|
<div class="row justify-content-start mb-2">
|
||||||
<div :class="messageWidthClass">
|
<div :class="messageWidthClass">
|
||||||
<div class="card bg-light border-0 text-dark">
|
<div class="card bg-light border-0 text-dark">
|
||||||
<div class="card-header" v-if="getFileContent['filesize'] !== 0">
|
|
||||||
<p class="card-text">
|
<div v-for="attachment in message.attachments" :key="attachment.id" class="card-header">
|
||||||
{{ getFileContent["filename"] }} |
|
<div class="btn-group w-100" role="group">
|
||||||
{{ getFileContent["filesize"] }} Bytes |
|
<button class="btn btn-light text-truncate" disabled>{{ attachment.name }}</button>
|
||||||
{{ getFileContent["filetype"] }}
|
<button @click="downloadAttachment(attachment.hash_sha512, attachment.name)" class="btn btn-light w-25"><i class="bi bi-download strong"></i></button>
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p class="card-text">{{ message.body }}</p>
|
<p class="card-text">{{ message.body }}</p>
|
||||||
|
@ -33,14 +33,7 @@
|
||||||
<i class="bi bi-info-circle"></i>
|
<i class="bi bi-info-circle"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
|
||||||
disabled
|
|
||||||
v-if="getFileContent['filesize'] !== 0"
|
|
||||||
class="btn btn-outline-secondary border-0 me-1"
|
|
||||||
@click="downloadAttachment"
|
|
||||||
>
|
|
||||||
<i class="bi bi-download"></i>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button class="btn btn-outline-secondary border-0" @click="deleteMessage">
|
<button class="btn btn-outline-secondary border-0" @click="deleteMessage">
|
||||||
<i class="bi bi-trash"></i>
|
<i class="bi bi-trash"></i>
|
||||||
|
@ -61,7 +54,6 @@ import { atob_FD } from "../js/freedata";
|
||||||
import { setActivePinia } from "pinia";
|
import { setActivePinia } from "pinia";
|
||||||
import pinia from "../store/index";
|
import pinia from "../store/index";
|
||||||
setActivePinia(pinia);
|
setActivePinia(pinia);
|
||||||
import { saveAs } from "file-saver";
|
|
||||||
|
|
||||||
import { useChatStore } from "../store/chatStore.js";
|
import { useChatStore } from "../store/chatStore.js";
|
||||||
const chat = useChatStore(pinia);
|
const chat = useChatStore(pinia);
|
||||||
|
@ -80,40 +72,42 @@ export default {
|
||||||
deleteMessage() {
|
deleteMessage() {
|
||||||
deleteMessageFromDB(this.message.id);
|
deleteMessageFromDB(this.message.id);
|
||||||
},
|
},
|
||||||
async downloadAttachment() {
|
async downloadAttachment(hash_sha512, fileName) {
|
||||||
try {
|
try {
|
||||||
// reset file store
|
const jsondata = await getMessageAttachment(hash_sha512);
|
||||||
chat.downloadFileFromDB = [];
|
const byteCharacters = atob(jsondata.data);
|
||||||
|
const byteArrays = [];
|
||||||
|
|
||||||
const attachment = await getMessageAttachment(this.message.id);
|
for (let offset = 0; offset < byteCharacters.length; offset += 512) {
|
||||||
const blob = new Blob([atob_FD(attachment[2])], {
|
const slice = byteCharacters.slice(offset, offset + 512);
|
||||||
type: `${attachment[1]};charset=utf-8`,
|
const byteNumbers = new Array(slice.length);
|
||||||
});
|
for (let i = 0; i < slice.length; i++) {
|
||||||
window.focus();
|
byteNumbers[i] = slice.charCodeAt(i);
|
||||||
saveAs(blob, attachment[0]);
|
}
|
||||||
|
const byteArray = new Uint8Array(byteNumbers);
|
||||||
|
byteArrays.push(byteArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
const blob = new Blob(byteArrays, { type: jsondata.type });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
// Creating a temporary anchor element to download the file
|
||||||
|
const anchor = document.createElement('a');
|
||||||
|
anchor.href = url;
|
||||||
|
anchor.download = fileName;
|
||||||
|
document.body.appendChild(anchor);
|
||||||
|
anchor.click();
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
document.body.removeChild(anchor);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to download attachment:", error);
|
console.error("Failed to download the attachment:", error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
getFileContent() {
|
|
||||||
if (this.message.attachments.length <= 0) {
|
|
||||||
return { filename: "", filesize: 0, filetype: "" };
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
var filename = Object.keys(this.message._attachments)[0];
|
|
||||||
var filesize = this.message._attachments[filename]["length"];
|
|
||||||
var filetype = filename.split(".")[1];
|
|
||||||
|
|
||||||
return { filename: filename, filesize: filesize, filetype: filetype };
|
|
||||||
} catch (e) {
|
|
||||||
console.log("file not loaded from database - empty?");
|
|
||||||
// we are only checking against filesize for displaying attachments
|
|
||||||
return { filesize: 0 };
|
|
||||||
}
|
|
||||||
},
|
|
||||||
messageWidthClass() {
|
messageWidthClass() {
|
||||||
// Calculate a Bootstrap grid class based on message length
|
// Calculate a Bootstrap grid class based on message length
|
||||||
// Adjust the logic as needed to fit your requirements
|
// Adjust the logic as needed to fit your requirements
|
||||||
|
|
|
@ -2,14 +2,6 @@
|
||||||
<div class="row justify-content-end mb-2">
|
<div class="row justify-content-end mb-2">
|
||||||
<!-- control area -->
|
<!-- control area -->
|
||||||
<div class="col-auto p-0 m-0">
|
<div class="col-auto p-0 m-0">
|
||||||
<button
|
|
||||||
disabled
|
|
||||||
v-if="getFileContent['filesize'] !== 0"
|
|
||||||
class="btn btn-outline-secondary border-0 me-1"
|
|
||||||
@click="downloadAttachment"
|
|
||||||
>
|
|
||||||
<i class="bi bi-download"></i>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="btn btn-outline-secondary border-0 me-1"
|
class="btn btn-outline-secondary border-0 me-1"
|
||||||
|
@ -32,17 +24,17 @@
|
||||||
<i class="bi bi-trash"></i>
|
<i class="bi bi-trash"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- message area -->
|
<!-- message area -->
|
||||||
<div :class="messageWidthClass">
|
<div :class="messageWidthClass">
|
||||||
<div class="card bg-secondary text-white">
|
<div class="card bg-secondary text-white">
|
||||||
<div class="card-header" v-if="getFileContent['filesize'] !== 0">
|
<div v-for="attachment in message.attachments" :key="attachment.id" class="card-header">
|
||||||
<p class="card-text">
|
<div class="btn-group w-100" role="group">
|
||||||
{{ getFileContent["filename"] }} |
|
<button class="btn btn-light text-truncate" disabled>{{ attachment.name }}</button>
|
||||||
{{ getFileContent["filesize"] }} Bytes |
|
<button @click="downloadAttachment(attachment.hash_sha512, attachment.name)" class="btn btn-light w-25"><i class="bi bi-download strong"></i></button>
|
||||||
{{ getFileContent["filetype"] }}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p class="card-text">{{ message.body }}</p>
|
<p class="card-text">{{ message.body }}</p>
|
||||||
|
@ -101,7 +93,6 @@ import {
|
||||||
import { setActivePinia } from "pinia";
|
import { setActivePinia } from "pinia";
|
||||||
import pinia from "../store/index";
|
import pinia from "../store/index";
|
||||||
setActivePinia(pinia);
|
setActivePinia(pinia);
|
||||||
import { saveAs } from "file-saver";
|
|
||||||
|
|
||||||
import { useChatStore } from "../store/chatStore.js";
|
import { useChatStore } from "../store/chatStore.js";
|
||||||
const chat = useChatStore(pinia);
|
const chat = useChatStore(pinia);
|
||||||
|
@ -126,42 +117,41 @@ export default {
|
||||||
//console.log(this.infoModal)
|
//console.log(this.infoModal)
|
||||||
//this.infoModal.show()
|
//this.infoModal.show()
|
||||||
},
|
},
|
||||||
async downloadAttachment() {
|
async downloadAttachment(hash_sha512, fileName) {
|
||||||
try {
|
try {
|
||||||
// reset file store
|
const jsondata = await getMessageAttachment(hash_sha512);
|
||||||
chat.downloadFileFromDB = [];
|
const byteCharacters = atob(jsondata.data);
|
||||||
|
const byteArrays = [];
|
||||||
|
|
||||||
const attachment = await getMessageAttachment(this.message.id);
|
for (let offset = 0; offset < byteCharacters.length; offset += 512) {
|
||||||
const blob = new Blob([atob_FD(attachment[2])], {
|
const slice = byteCharacters.slice(offset, offset + 512);
|
||||||
type: `${attachment[1]};charset=utf-8`,
|
const byteNumbers = new Array(slice.length);
|
||||||
});
|
for (let i = 0; i < slice.length; i++) {
|
||||||
saveAs(blob, attachment[0]);
|
byteNumbers[i] = slice.charCodeAt(i);
|
||||||
|
}
|
||||||
|
const byteArray = new Uint8Array(byteNumbers);
|
||||||
|
byteArrays.push(byteArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
const blob = new Blob(byteArrays, { type: jsondata.type });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
// Creating a temporary anchor element to download the file
|
||||||
|
const anchor = document.createElement('a');
|
||||||
|
anchor.href = url;
|
||||||
|
anchor.download = fileName;
|
||||||
|
document.body.appendChild(anchor);
|
||||||
|
anchor.click();
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
document.body.removeChild(anchor);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to download attachment:", error);
|
console.error("Failed to download the attachment:", error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
getFileContent() {
|
|
||||||
if (this.message.attachments.length <= 0) {
|
|
||||||
return { filename: "", filesize: 0, filetype: "" };
|
|
||||||
}
|
|
||||||
|
|
||||||
var filename = Object.keys(this.message._attachments)[0];
|
|
||||||
var filesize = this.message._attachments[filename]["length"];
|
|
||||||
var filetype = filename.split(".")[1];
|
|
||||||
|
|
||||||
// ensure filesize is 0 for hiding message header if no data is available
|
|
||||||
if (
|
|
||||||
typeof filename === "undefined" ||
|
|
||||||
filename === "" ||
|
|
||||||
filename === "-"
|
|
||||||
) {
|
|
||||||
filesize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return { filename: filename, filesize: filesize, filetype: filetype };
|
|
||||||
},
|
|
||||||
messageWidthClass() {
|
messageWidthClass() {
|
||||||
// Calculate a Bootstrap grid class based on message length
|
// Calculate a Bootstrap grid class based on message length
|
||||||
// Adjust the logic as needed to fit your requirements
|
// Adjust the logic as needed to fit your requirements
|
||||||
|
|
|
@ -44,34 +44,72 @@ chat.inputText += detail.unicode
|
||||||
const chatModuleMessage=ref(null);
|
const chatModuleMessage=ref(null);
|
||||||
|
|
||||||
|
|
||||||
|
// Function to trigger the hidden file input
|
||||||
|
function triggerFileInput() {
|
||||||
|
fileInput.value.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function transmitNewMessage(){
|
// Use a ref for storing multiple files
|
||||||
|
const selectedFiles = ref([]);
|
||||||
|
const fileInput = ref(null);
|
||||||
|
|
||||||
|
function handleFileSelection(event) {
|
||||||
|
// Reset previously selected files
|
||||||
|
selectedFiles.value = [];
|
||||||
|
|
||||||
// if no callsign is selected, assume we are using the first one..
|
// Process each file
|
||||||
if(typeof(chat.selectedCallsign) == 'undefined'){
|
for (let file of event.target.files) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = () => {
|
||||||
|
// Convert file content to base64
|
||||||
|
const base64Content = btoa(reader.result); // Adjust this line if necessary
|
||||||
|
selectedFiles.value.push({
|
||||||
|
name: file.name,
|
||||||
|
size: file.size,
|
||||||
|
type: file.type,
|
||||||
|
content: base64Content, // Store base64 encoded content
|
||||||
|
});
|
||||||
|
};
|
||||||
|
reader.readAsBinaryString(file); // Read the file content as binary string
|
||||||
|
}
|
||||||
|
}function transmitNewMessage() {
|
||||||
|
// Check if a callsign is selected, default to the first one if not
|
||||||
|
if (typeof(chat.selectedCallsign) === 'undefined') {
|
||||||
chat.selectedCallsign = Object.keys(chat.callsign_list)[0];
|
chat.selectedCallsign = Object.keys(chat.callsign_list)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
chat.inputText = chat.inputText.trim();
|
chat.inputText = chat.inputText.trim();
|
||||||
if (chat.inputText.length==0 && chat.inputFileName == "-")
|
|
||||||
return;
|
// Proceed only if there is text or files selected
|
||||||
|
if (chat.inputText.length === 0 && selectedFiles.value.length === 0) return;
|
||||||
|
|
||||||
|
const attachments = selectedFiles.value.map(file => {
|
||||||
|
return {
|
||||||
|
name: file.name,
|
||||||
|
type: file.type,
|
||||||
|
data: file.content
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
if (chat.selectedCallsign.startsWith("BC-")) {
|
if (chat.selectedCallsign.startsWith("BC-")) {
|
||||||
|
// Handle broadcast message differently if needed
|
||||||
return "new broadcast"
|
return "new broadcast";
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
//newMessage(chat.selectedCallsign, chat.inputText, chat.inputFile, chat.inputFileName, chat.inputFileSize, chat.inputFileType)
|
// If there are attachments, send them along with the message
|
||||||
newMessage(chat.selectedCallsign, chat.inputText)
|
if (attachments.length > 0) {
|
||||||
|
newMessage(chat.selectedCallsign, chat.inputText, attachments);
|
||||||
|
} else {
|
||||||
|
// Send text only if no attachments are selected
|
||||||
|
newMessage(chat.selectedCallsign, chat.inputText);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// finally do a cleanup
|
|
||||||
//chatModuleMessage.reset();
|
// Cleanup after sending message
|
||||||
chat.inputText = '';
|
chat.inputText = '';
|
||||||
chatModuleMessage.value="";
|
chatModuleMessage.value = "";
|
||||||
// @ts-expect-error
|
selectedFiles.value = []; // Clear selected files after sending
|
||||||
resetFile()
|
// Reset any other states or UI elements as necessary
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetFile(event){
|
function resetFile(event){
|
||||||
|
@ -140,9 +178,9 @@ function calculateTimeNeeded(){
|
||||||
return obj.snr === snrList[i].snr
|
return obj.snr === snrList[i].snr
|
||||||
})
|
})
|
||||||
|
|
||||||
calculatedSpeedPerMinutePER0.push(chat.inputFileSize / result.bpm)
|
calculatedSpeedPerMinutePER0.push(totalSize / result.bpm)
|
||||||
calculatedSpeedPerMinutePER25.push(chat.inputFileSize / (result.bpm * 0.75))
|
calculatedSpeedPerMinutePER25.push(totalSize / (result.bpm * 0.75))
|
||||||
calculatedSpeedPerMinutePER75.push(chat.inputFileSize / (result.bpm * 0.25))
|
calculatedSpeedPerMinutePER75.push(totalSize / (result.bpm * 0.25))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,11 +240,11 @@ const speedChartData = computed(() => ({
|
||||||
|
|
||||||
|
|
||||||
<!-- trigger file selection modal -->
|
<!-- trigger file selection modal -->
|
||||||
<!--
|
|
||||||
<button type="button" class="btn btn-outline-secondary border-0 rounded-pill me-1" data-bs-toggle="modal" data-bs-target="#fileSelectionModal">
|
<button type="button" class="btn btn-outline-secondary border-0 rounded-pill me-1" data-bs-toggle="modal" data-bs-target="#fileSelectionModal">
|
||||||
<i class="bi bi-paperclip" style="font-size: 1.2rem"></i>
|
<i class="bi bi-paperclip" style="font-size: 1.2rem"></i>
|
||||||
</button>
|
</button>
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
<textarea
|
<textarea
|
||||||
|
@ -264,20 +302,54 @@ const speedChartData = computed(() => ({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
<div class="input-group-text mb-3">
|
<div class="input-group-text mb-3">
|
||||||
<input class="" type="file" ref="doc" @change="readFile" />
|
<input class="" type="file" ref="doc" @change="readFile" />
|
||||||
</div>
|
</div>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<div class="container w-100 mb-3">
|
||||||
|
<!-- Button that user will click to open file dialog -->
|
||||||
|
<button class="btn btn-primary w-100" @click="triggerFileInput">Attach Files</button>
|
||||||
|
|
||||||
|
<!-- Hidden file input -->
|
||||||
|
<input type="file" multiple ref="fileInput" @change="handleFileSelection" style="display: none;" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container-fluid px-0">
|
||||||
|
<div class="d-flex flex-row overflow-auto bg-light rounded-3 p-2 border border-1">
|
||||||
|
<div v-for="(file, index) in selectedFiles" :key="index" class="pe-2">
|
||||||
|
<div class="card" style=" min-width: 10rem; max-width: 10rem;">
|
||||||
|
<!-- Card Header with Remove Button -->
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<span class="text-truncate">{{ file.name }}</span>
|
||||||
|
<button class="btn btn-close" @click="removeFile(index)"></button>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p class="card-text">...</p>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer text-muted">
|
||||||
|
{{ file.type }}
|
||||||
|
</div>
|
||||||
|
<div class="card-footer text-muted">
|
||||||
|
{{ file.size }} bytes
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
|
||||||
<div class="btn-group me-2" role="group" aria-label="Basic outlined example">
|
<div class="btn-group me-2" role="group" aria-label="Basic outlined example">
|
||||||
<button type="button" class="btn btn-secondary">Type</button>
|
<button type="button" class="btn btn-secondary">total size</button>
|
||||||
<button type="button" class="btn btn-secondary disabled">{{chat.inputFileType}}</button>
|
<button type="button" class="btn btn-secondary disabled">{{chat.inputFileSize}} {{totalSizeFormatted}}</button>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="btn-group me-2" role="group" aria-label="Basic outlined example">
|
|
||||||
<button type="button" class="btn btn-secondary">Size</button>
|
|
||||||
<button type="button" class="btn btn-secondary disabled">{{chat.inputFileSize}}</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Line :data="speedChartData" />
|
<Line :data="speedChartData" />
|
||||||
|
|
|
@ -155,10 +155,16 @@ export async function getFreedataMessages() {
|
||||||
processFreedataMessages(res);
|
processFreedataMessages(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function sendFreedataMessage(destination, body) {
|
export async function getFreedataAttachmentBySha512(data_sha512) {
|
||||||
|
let res = await apiGet(`/freedata/messages/attachment/${data_sha512}`);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sendFreedataMessage(destination, body, attachments) {
|
||||||
return await apiPost("/freedata/messages", {
|
return await apiPost("/freedata/messages", {
|
||||||
destination: destination,
|
destination: destination,
|
||||||
body: body,
|
body: body,
|
||||||
|
attachments: attachments,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
sendFreedataMessage,
|
sendFreedataMessage,
|
||||||
deleteFreedataMessage,
|
deleteFreedataMessage,
|
||||||
retransmitFreedataMessage,
|
retransmitFreedataMessage,
|
||||||
|
getFreedataAttachmentBySha512,
|
||||||
} from "./api";
|
} from "./api";
|
||||||
|
|
||||||
interface Message {
|
interface Message {
|
||||||
|
@ -76,8 +77,9 @@ function createSortedMessagesList(data: {
|
||||||
return callsignMessages;
|
return callsignMessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function newMessage(dxcall, body) {
|
export function newMessage(dxcall, body, attachments) {
|
||||||
sendFreedataMessage(dxcall, body);
|
console.log(attachments)
|
||||||
|
sendFreedataMessage(dxcall, body, attachments);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------ TEMPORARY DUMMY FUNCTIONS --- */
|
/* ------ TEMPORARY DUMMY FUNCTIONS --- */
|
||||||
|
@ -99,6 +101,6 @@ export function requestMessageInfo(id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMessageAttachment(id) {
|
export async function getMessageAttachment(data_sha512) {
|
||||||
return;
|
return await getFreedataAttachmentBySha512(data_sha512)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ def validate_freedata_callsign(callsign):
|
||||||
return re.compile(regexp).match(callsign) is not None
|
return re.compile(regexp).match(callsign) is not None
|
||||||
|
|
||||||
def validate_message_attachment(attachment):
|
def validate_message_attachment(attachment):
|
||||||
|
print(attachment)
|
||||||
for field in ['name', 'type', 'data']:
|
for field in ['name', 'type', 'data']:
|
||||||
if field not in attachment:
|
if field not in attachment:
|
||||||
raise ValueError(f"Attachment missing '{field}'")
|
raise ValueError(f"Attachment missing '{field}'")
|
||||||
|
|
|
@ -64,3 +64,18 @@ class DatabaseManagerAttachments(DatabaseManager):
|
||||||
def get_attachments_by_message_id_json(self, message_id):
|
def get_attachments_by_message_id_json(self, message_id):
|
||||||
attachments = self.get_attachments_by_message_id(message_id)
|
attachments = self.get_attachments_by_message_id(message_id)
|
||||||
return json.dumps(attachments)
|
return json.dumps(attachments)
|
||||||
|
|
||||||
|
def get_attachment_by_sha512(self, hash_sha512):
|
||||||
|
session = self.get_thread_scoped_session()
|
||||||
|
try:
|
||||||
|
attachment = session.query(Attachment).filter_by(hash_sha512=hash_sha512).first()
|
||||||
|
if attachment:
|
||||||
|
return attachment.to_dict() # Assuming you have a to_dict method
|
||||||
|
else:
|
||||||
|
self.log(f"No attachment found with SHA-512 hash: {hash_sha512}")
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
self.log(f"Error fetching attachment with SHA-512 hash {hash_sha512}: {e}", isWarning=True)
|
||||||
|
return None
|
||||||
|
finally:
|
||||||
|
session.remove()
|
|
@ -114,7 +114,7 @@ class Attachment(Base):
|
||||||
return {
|
return {
|
||||||
'id': self.id,
|
'id': self.id,
|
||||||
'name': self.name,
|
'name': self.name,
|
||||||
'data_type': self.data_type,
|
'type': self.data_type,
|
||||||
'data': self.data,
|
'data': self.data,
|
||||||
'checksum_crc32': self.checksum_crc32,
|
'checksum_crc32': self.checksum_crc32,
|
||||||
'hash_sha512' : self.hash_sha512
|
'hash_sha512' : self.hash_sha512
|
||||||
|
|
|
@ -274,6 +274,11 @@ def get_message_attachments(message_id):
|
||||||
attachments = DatabaseManagerAttachments(app.event_manager).get_attachments_by_message_id_json(message_id)
|
attachments = DatabaseManagerAttachments(app.event_manager).get_attachments_by_message_id_json(message_id)
|
||||||
return api_response(attachments)
|
return api_response(attachments)
|
||||||
|
|
||||||
|
@app.route('/freedata/messages/attachment/<string:data_sha512>', methods=['GET'])
|
||||||
|
def get_message_attachment(data_sha512):
|
||||||
|
attachment = DatabaseManagerAttachments(app.event_manager).get_attachment_by_sha512(data_sha512)
|
||||||
|
return api_response(attachment)
|
||||||
|
|
||||||
@app.route('/freedata/beacons', methods=['GET'])
|
@app.route('/freedata/beacons', methods=['GET'])
|
||||||
def get_all_beacons():
|
def get_all_beacons():
|
||||||
beacons = DatabaseManagerBeacon(app.event_manager).get_all_beacons()
|
beacons = DatabaseManagerBeacon(app.event_manager).get_all_beacons()
|
||||||
|
|
Loading…
Reference in a new issue