drawing.pug:
extends ../layouts/_layout.pug
block variables
- var activePage = 'Drawings';
- var activeGroup = 'none';
block content
.app-title
div
h1
i.bi.bi-speedometer
| #{title}
ul.app-breadcrumb.breadcrumb
li.breadcrumb-item
i.bi.bi-house-door.fs-6
li.breadcrumb-item
a(href='#') #{title}
.row
.col-md-12
.tile
.tile-title-w-btn
h3.title List of #{title}
p
button.btn.btn-primary.icon-btn(type="button", id="addFirmBtn", onclick="openFirmModal('Add', '')", data-bs-toggle="modal", data-bs-target="#modalDialogScrollable")
i.bi.bi-plus-square.me-2
| Add
.tile-body
.table-responsive
table.table.table-hover.table-bordered#sampleTable
thead
tr
th #
th Drawing Name
th Bucket Name
th Uploded Drawing
th Type
th Documents
th GEO Cordinates
th Status
th Action
tbody
//- Popup Form
div#modalDialogScrollable.modal.fade(tabindex="-1")
div.modal-dialog.modal-dialog-scrollable
div.modal-content
div.modal-header
h5.modal-title #{modalTitle}
button.btn-close(type="button", data-bs-dismiss="modal" aria-label="Close")
//- Form Fields
form#firmForm(method="POST", action="javascript:void(0);", enctype="multipart/form-data")
input#clientId(type="hidden" name="clientId" value=session.user.data.client_id)
div.modal-body
//- Firm Name
div.form-group
label(for="drawing_name") Drawing Name
input#drawing_name.form-control(type="text", placeholder="Enter Drawing Name" name="drawing_name")
div.form-group
label(for="bucket_id") Bucket
select#bucket_id.form-control(name="bucket_id")
option(value="") -- Select Bucket --
div.form-group
label(for="upload") Upload Drawing
input#upload.form-control(type="file" name="upload")
div.form-group
label(for="drawing_doc") Upload Drawing Doc
small (PDF, PPT only)
input#drawing_doc.form-control(type="file" name="drawing_doc")
//- Latitude and Longitude
div.form-group
label Latitude and Longitude
table.table.table-hover.table-bordered#latLngTable
thead
tr
th Latitude
th Longitude
th Action
tbody
tr
td
input#latitude.form-control(type="text" name="latitude[]")
td
input#longitude.form-control(type="text" name="longitude[]")
td
tr
td
input#latitude.form-control(type="text" name="latitude[]")
td
input#longitude.form-control(type="text" name="longitude[]")
td
tr
td
input#latitude.form-control(type="text" name="latitude[]")
td
input#longitude.form-control(type="text" name="longitude[]")
td
//- Button to add Latitude and Longitude row
button#addLatLngBtn.btn.btn-primary(type="button") Add Latitude/Longitude
div.modal-footer
button.btn.btn-secondary(type="button", data-bs-dismiss="modal") Close
button#saveFirmBtn.btn.btn-primary(type="button", onclick="submitForm()") Save
block specific-js
block specific-js
link(rel="stylesheet" href="https://cdn.datatables.net/v/bs5/dt-1.13.4/datatables.min.css")
//- Data table plugin
script(type='text/javascript', src="/js/plugins/jquery.dataTables.min.js")
script(type='text/javascript').
var activeStatus = 1;
$(document).ready(function() {
//$('#sampleTable').DataTable();
loadTableData(activeStatus);
// Fetch backets from clientMaster/getDepartment
var clientId = $('#clientId').val();
$.ajax({
url: '/client/getClientBuckets/' + clientId,
type: 'GET',
success: function(response) {
if (response.status === 1) {
$('#bucket_id').empty().append('<option value="">-- Select Bucket --</option>');
$.each(response.data, function(key, value) {
$('#bucket_id').append('<option value="' + value.bucket_id + '">' + value.bucket_name + '</option>');
});
} else {
console.error('Failed to fetch Bucket:', response.error);
}
},
error: function(xhr, status, error) {
console.error('Error fetching Bucket:', error);
}
});
// Add Latitude and Longitude row
$('#addLatLngBtn').click(function() {
$('#latLngTable tbody').append(
`<tr>
<td><input type="text" class="form-control" name="latitude[]"></td>
<td><input type="text" class="form-control" name="longitude[]"></td>
<td><button type="button" class="btn btn-danger remove-row">Remove</button></td>
</tr>`
);
});
// Remove Latitude and Longitude row
$('#latLngTable').on('click', '.remove-row', function() {
$(this).closest('tr').remove();
});
});
function loadTableData(event) {
var url = `/drawing/getDrawing?status=${event}`;
if(event == '*'){
url = `/drawing/getDrawing`;
}
$.ajax({
url: url,
type: 'GET',
success: function(response) {
if (response.status === 1) {
var tableData = response.data;
populateTable(tableData);
} else {
console.error('Failed to fetch table data:', response.error);
}
},
error: function(xhr, status, error) {
console.error('Error fetching table data:', error);
}
});
}
function populateTable(data) {
var tbody = $('#sampleTable tbody');
tbody.empty(); // Clear existing table body
if (data && data.length > 0) {
data.forEach(function(element, index) {
console.log('element', element);
var row = $('<tr>');
row.append($('<td>').text(index + 1));
row.append($('<td>').text(element.drawing_name));
row.append($('<td>').text(element.bucket_name));
row.append($('<td>').text(element.drawing_upload));
row.append($('<td>').text(element.drawing_type));
row.append($('<td>').text(element.drawing_doc));
row.append($('<td>').text(element.g_cordinates));
if(element.is_active == 1){
row.append($('<td>').text('Activated'));
}else{
row.append($('<td>').text('Inactivated'));
}
var actionBtns = $('<td>');
var editBtn = $('<button>').addClass('btn btn-primary icon-btn').attr('type', 'button').attr('onclick', 'openFirmModal(\'Edit\', ' + JSON.stringify(element) + ')').attr('data-bs-toggle', 'modal').attr('data-bs-target', '#modalDialogScrollable').html('<i class="bi bi-pencil me-2"></i>Edit');
var statusBtn = $('<button>').addClass('btn btn-' + (element.is_active == 0 ? 'success' : 'danger') + ' icon-btn').attr('type', 'button').attr('onclick', 'StatusChange(' + (element.is_active == 0 ? 1 : 0) + ', ' + JSON.stringify(element) + ')').html('<i class="bi bi-' + (element.is_active == 0 ? 'check-circle' : 'x-circle') + ' me-2"></i>' + (element.is_active == 0 ? 'Active' : 'Inactive'));
var trnslateBtn = $('<button>').addClass('btn btn-success icon-btn').attr('type', 'button').attr('onclick', 'getTrtranslation(' + JSON.stringify(element.drawing_id) + ')').html('Trtranslation');
actionBtns.append(editBtn);
actionBtns.append(statusBtn);
actionBtns.append(trnslateBtn);
row.append(actionBtns);
tbody.append(row);
});
$('#sampleTable').DataTable();
} else {
tbody.append('<tr><td colspan="9">No data available</td></tr>');
}
}
function openFirmModal(formType, element) {
var modalTitle = '';
var formAction = '';
if (formType === 'Add') {
modalTitle = 'Upload Drawing';
formAction = '/drawing/addDrawing';
} else if (formType === 'Edit' && element) {
modalTitle = 'Edit Uploaded Drawing';
formAction = '/drawing/updateDepartment/' + element.department_id;
// Set form field values
document.getElementById('department_name').value = element.department_name;
document.getElementById('department_desc').value = element.department_desc;
}
// Set form action
document.getElementById('firmForm').action = formAction;
// Set modal title
document.querySelector('.modal-title').textContent = modalTitle;
}
function submitForm() {
var formAction = document.getElementById('firmForm').action;
// Collect latitude and longitude points
var coordinates = [];
$('#latLngTable tbody tr').each(function() {
var latitude = $(this).find('input[name="latitude[]"]').val();
var longitude = $(this).find('input[name="longitude[]"]').val();
coordinates.push({ lat: latitude, lng: longitude });
});
var formData = {
drawing_name: document.getElementById('drawing_name').value,
bucket_id: document.getElementById('bucket_id').value,
g_cordinates: JSON.stringify(coordinates)
};
console.log("formData", formData);
// Send AJAX request
$.ajax({
url: formAction,
type: 'POST',
data: formData,
success: function(response) {
if (response.status === 1) {
var drawing_id = response.data.drawing_id;
uploadDrawingDocs(drawing_id);
} else {
alert('Error: ' + response.message);
}
},
error: function(xhr, status, error) {
console.error('Error:', error);
alert('An error occurred while submitting the form. Please try again later.');
}
});
}
function uploadDrawingDocs(drawing_id) {
var formData = new FormData();
formData.append('file', document.getElementById('drawing_doc').files[0]);
$.ajax({
url: '/drawing/uploadDrawingDocs/' + drawing_id,
type: 'POST',
data: formData,
contentType: false,
processData: false,
success: function(response) {
if (response.status === 1) {
uploadDrawings(drawing_id);
} else {
alert('Error: ' + response.message);
}
},
error: function(xhr, status, error) {
console.error('Error:', error);
alert('An error occurred while submitting document. Please try again later.');
}
});
}
function uploadDrawings(drawing_id) {
var formDrawingData = new FormData();
formDrawingData.append('file', document.getElementById('upload').files[0]);
console.log('formDrawingData', formDrawingData);
$.ajax({
url: '/drawing/uploadDrawings/' + drawing_id,
type: 'POST',
data: formDrawingData,
contentType: false,
processData: false,
success: function(response) {
if (response.status === 1) {
alert(response.message);
location.reload();
} else {
alert('Error: ' + response.message);
}
},
error: function(xhr, status, error) {
console.error('Error:', error);
alert('An error occurred while submitting the drawing. Please try again later.');
}
});
}
function getTrtranslation(drawing_id){
console.log('drawing_id', drawing_id);
$.ajax({
url: '/drawing/uploadDrawingTranslation/' + drawing_id,
type: 'GET',
success: function(response) {
if (response.status === 1) {
console.log('response', response);
} else {
console.error('Failed to fetch table data:', response.error);
}
},
error: function(xhr, status, error) {
console.error('Error fetching table data:', error);
}
});
}
drawing.controller.js code:
const { DataManagementClient, ModelDerivativeClient } = require('forge-server-utils');
const fs = require('fs');
const path = require('path');
const configAPS = require('../../config');
const { getModels } = require('../../databases/mysql');
const { authenticate } = require('../../services/authenticationService');
const { UtilsServices } = require('../../services/index')
const multer = require('multer');
// Initialize Forge clients
const dataClient = new DataManagementClient(configAPS.credentials);
const derivativeClient = new ModelDerivativeClient(configAPS.credentials);
// Configure multer storage
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/uploads/drawing-docs');
},
filename: function (req, file, cb) {
if (!req.params.id) {
return cb(new Error('Drawing ID is missing'));
}
// File name will be drawing_id + current timestamp + original file extension
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
cb(null, `${req.params.drawing_id}-${uniqueSuffix}${path.extname(file.originalname)}`);
}
});
// Configure multer storage for uploadDrawings
const uploadDrawingsStorage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/uploads/drawings');
},
filename: function (req, file, cb) {
if (!req.params.id) {
return cb(new Error('Drawing ID is missing'));
}
// File name will be drawing_id + current timestamp + original file extension
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
cb(null, `${req.params.drawing_id}-${uniqueSuffix}${path.extname(file.originalname)}`);
}
});
// Initialize multer upload for uploadDrawings
const uploadDrawings = multer({ storage: uploadDrawingsStorage }).single('file');
// Initialize multer upload
const upload = multer({ storage: storage }).single('file');
module.exports = {
addDrawing: async (req, res) => {
let body = req.body;
let response = { status: 0 }
if (body.drawing_name) {
req.body.created_by = req.session.user.data.user_id;
body.client_id = req.session.user.data.client_id;
getModels().drawings.build(req.body).save().then(async (drawings) => {
response.status = 1;
response.data = drawings.dataValues;
res.status(200).send(response)
}).catch((err) => {
res.status(200).send(UtilsServices.errorHandler(err))
});
} else {
res.send({ status: 0, message: "invalid parameters" })
}
},
uploadDrawingDocs: async (req, res) => {
let body = req.body;
let query = { drawing_id: req.params.id };
let drawing = await getModels().drawings.findOne({ where: query });
if (!drawing) {
return res.status(404).json({ status: 0, message: 'Drawing not found' });
}
// Call the multer upload middleware
upload(req, res, async function (err) {
if (err) {
console.error('Error uploading file:', err);
return res.status(500).json({ status: 0, message: 'Error uploading file' });
}
// Check if file was uploaded
if (!req.file) {
return res.status(400).json({ status: 0, message: 'No file uploaded' });
}
// File uploaded successfully, you can handle further logic here
let fileName = req.file.filename;
let data = { 'drawing_doc': fileName }
let date = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')
data.updated_at = date;
drawing.update(data);
res.status(200).send({
status: 1,
message: "Updated successfully!",
data: drawing
})
});
},
uploadDrawings: async (req, res) => {
let body = req.body;
console.log('req.params.id', req.params.id);
// Call the multer upload middleware
uploadDrawings(req, res, async function (err) {
if (err) {
console.error('Error uploading file:', err);
return res.status(500).json({ status: 0, message: 'Error uploading file' });
}
// Check if file was uploaded
if (!req.file) {
return res.status(400).json({ status: 0, message: 'No file uploaded' });
}
try {
let query = { drawing_id: req.params.id };
let drawing = await getModels().drawings.findOne({ where: query });
if (!drawing) {
return res.status(404).json({ status: 0, message: 'Drawing not found' });
}
let query2 = { bucket_id: drawing.bucket_id };
let bucket = await getModels().buckets.findOne({ where: query2 });
if (!bucket) {
return res.status(404).json({ status: 0, message: 'Bucket not found' });
}
// Authenticate with Forge
const token = await authenticate(); // Implement your authentication logic
// Read the file data
const fileData = fs.readFileSync(req.file.path);
// Set the bucket key, object key, and upload options
const bucketKey = bucket.bucket_name;
const objectKey = req.file.originalname;
const options = {};
// Upload the file to the Forge bucket
const uploadedObject = await dataClient.uploadObject(bucketKey, objectKey, fileData, options);
console.log('Object uploaded successfully:', uploadedObject);
let urn = Buffer.from(uploadedObject.objectId).toString('base64');
let pathInArchive = uploadedObject.location;
// Store the URN in the database
let fileName = req.file.originalname;
let data = { 'drawing_upload': fileName, 'drawing_urn': urn, 'drawing_location': pathInArchive }
let date = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')
data.updated_at = date;
drawing.update(data);
res.status(200).json({
status: 1,
message: "File uploaded and translated successfully!",
data: { urn }
});
} catch (error) {
console.error('Error:', error);
res.status(500).json({ status: 0, message: 'An error occurred', error: error.message });
}
});
},
uploadDrawingTranslation: async (req, res) => {
console.log('req.params.id', req.params.id);
try {
let query = { drawing_id: req.params.id };
let drawing = await getModels().drawings.findOne({ where: query });
if (!drawing) {
return res.status(404).json({ status: 0, message: 'Drawing not found' });
}
let query2 = { bucket_id: drawing.bucket_id };
let bucket = await getModels().buckets.findOne({ where: query2 });
if (!bucket) {
return res.status(404).json({ status: 0, message: 'Bucket not found' });
}
const urn = drawing.drawing_urn;
const pathInArchive = drawing.drawing_location;
console.log('urn', urn);
const formats = [
{ type: 'svf', views: ['2d', '3d'] },
{ type: 'obj', views: ['2d', '3d'] },
{ type: 'dwg', views: ['2d', '3d'] },
{ type: 'stl', views: ['2d', '3d'] },
{ type: 'step', views: ['2d', '3d'] },
{ type: 'iges', views: ['2d', '3d'] },
{ type: 'thumbnail', views: ['2d', '3d'] },
{ type: 'fbx', views: ['2d', '3d'] },
{ type: 'ifc', views: ['2d', '3d'] },
{ type: 'f3d', views: ['2d', '3d'] },
{ type: 'pdf', views: ['2d', '3d'] },
];
const force = true; // or false based on your requirements
// Trigger the translation process
const job = await derivativeClient.submitJob(urn, formats, pathInArchive, force);
console.log('Job', job);
// Wait for translation to complete
let translationCompleted = false;
while (!translationCompleted) {
const manifest = await derivativeClient.getManifest(urn);
if (manifest.status === 'success') {
console.log('manifestSuccess', manifest);
translationCompleted = true;
} else if (manifest.status === 'failed') {
console.log('manifestFailed', manifest);
if(manifest.derivatives[0]){
console.log('manifestError', manifest.derivatives[0].messages);
}
throw new Error('Translation failed');
} else {
console.log('manifest', manifest);
if(manifest.derivatives[0]){
console.log('manifestError', manifest.derivatives[0].messages);
}
await new Promise(resolve => setTimeout(resolve, 5000)); // Wait for 5 seconds before checking again
}
}
// Translation completed, fetch metadata
const metadata = await derivativeClient.getMetadata(urn);
console.log('metadata', metadata);
// const metadataStream = await derivativeClient.getMetadataStream(urn);
// console.log('metadataStream', metadataStream);
} catch (error) {
console.error('Error:', error);
res.status(500).json({ status: 0, message: 'An error occurred', error: error.message });
}
},
};
我面临的问题是getManifest方法
当我在 https://oss-manager.autodesk.io/ 上传相同的文件时,它工作正常,所以我不认为我上传的绘图有问题。
所以我想要的是有任何错误,该错误是什么以及我如何修复它如果可能的话,我想在成功翻译后获取零件的所有 DBID 及其属性
getObjectDetails 端点,查找上传对象的字节大小,并查看它是否与您上传的原始文件的文件大小匹配。