# QDR Temporary Shared Storage - Integration Guide This guide provides instructions and examples for integrating the QDR Temporary Shared Storage plugin with various applications and systems. ## Table of Contents 1. [Web Applications](#web-applications) 2. [Mobile Applications](#mobile-applications) 3. [Desktop Applications](#desktop-applications) 4. [CRM Systems](#crm-systems) 5. [Document Management Systems](#document-management-systems) 6. [Email Systems](#email-systems) 7. [Workflow Automation](#workflow-automation) ## Web Applications ### Basic HTML Form Integration You can create a simple HTML form that interacts with the plugin's REST API. ```html File Upload

Upload a File

``` ### React Component Integration Create a reusable React component for file uploads: ```jsx import React, { useState } from 'react'; import axios from 'axios'; const FileUploader = ({ apiKey, apiUrl, onSuccess, onError }) => { const [file, setFile] = useState(null); const [description, setDescription] = useState(''); const [message, setMessage] = useState(''); const [password, setPassword] = useState(''); const [reference, setReference] = useState(''); const [activeDays, setActiveDays] = useState(30); const [progress, setProgress] = useState(0); const [uploading, setUploading] = useState(false); const handleFileChange = (e) => { setFile(e.target.files[0]); }; const handleSubmit = async (e) => { e.preventDefault(); if (!file) return; setUploading(true); setProgress(0); try { // Step 1: Initialize upload const initResponse = await axios.post(`${apiUrl}/upload/init`, { original_file_name: file.name, file_size: file.size }, { headers: { 'X-Api-Key': apiKey } }); const uploadId = initResponse.data.upload_id; // Step 2: Upload chunks const chunkSize = 1024 * 1024; // 1MB chunks const totalChunks = Math.ceil(file.size / chunkSize); for (let i = 0; i < totalChunks; i++) { const start = i * chunkSize; const end = Math.min(file.size, start + chunkSize); const chunk = file.slice(start, end); const formData = new FormData(); formData.append('upload_id', uploadId); formData.append('chunk_index', i); formData.append('total_chunks', totalChunks); formData.append('chunk', chunk); await axios.post(`${apiUrl}/upload/chunk`, formData, { headers: { 'X-Api-Key': apiKey } }); setProgress(Math.round((i + 1) / totalChunks * 100)); } // Step 3: Finalize upload const activeToDate = new Date(); activeToDate.setDate(activeToDate.getDate() + parseInt(activeDays)); const activeTo = activeToDate.toISOString().slice(0, 19).replace('T', ' '); const finalizeResponse = await axios.post(`${apiUrl}/upload/finalize`, { upload_id: uploadId, total_chunks: totalChunks, original_file_name: file.name, description, message, password, reference, active_to: activeTo }, { headers: { 'X-Api-Key': apiKey } }); setUploading(false); if (onSuccess) { onSuccess(finalizeResponse.data); } } catch (error) { setUploading(false); if (onError) { onError(error); } } }; return (
setDescription(e.target.value)} disabled={uploading} required />
``` ## CRM Systems ### Salesforce Integration You can integrate the plugin with Salesforce using Apex code to upload files and store the reference in Salesforce records. ```java public class QDRFileUploaderController { // API Configuration private static final String API_URL = 'https://your-wordpress-site.com/wp-json/qdr-tss/v1'; private static final String API_KEY = 'your-api-key-here'; // Upload a file to QDR Temporary Shared Storage @AuraEnabled public static Map uploadFile(String fileName, String fileContent, String description, String message, String password, String reference, Integer activeDays) { try { Blob fileBlob = EncodingUtil.base64Decode(fileContent); Integer fileSize = fileBlob.size(); // Step 1: Initialize upload HttpRequest initRequest = new HttpRequest(); initRequest.setEndpoint(API_URL + '/upload/init'); initRequest.setMethod('POST'); initRequest.setHeader('X-Api-Key', API_KEY); initRequest.setHeader('Content-Type', 'application/json'); Map initParams = new Map(); initParams.put('original_file_name', fileName); initParams.put('file_size', fileSize); initRequest.setBody(JSON.serialize(initParams)); Http http = new Http(); HttpResponse initResponse = http.send(initRequest); if (initResponse.getStatusCode() != 200) { throw new AuraHandledException('Failed to initialize upload: ' + initResponse.getBody()); } Map initResult = (Map) JSON.deserializeUntyped(initResponse.getBody()); String uploadId = (String) initResult.get('upload_id'); // Step 2: Upload chunks Integer chunkSize = 1024 * 1024; // 1MB chunks Integer totalChunks = Math.ceil(fileSize / (Double) chunkSize).intValue(); for (Integer i = 0; i < totalChunks; i++) { Integer start = i * chunkSize; Integer end = Math.min(fileSize, start + chunkSize); // Create chunk Blob chunkBlob = fileBlob.substring(start, end); String chunkBase64 = EncodingUtil.base64Encode(chunkBlob); // Upload chunk HttpRequest chunkRequest = new HttpRequest(); chunkRequest.setEndpoint(API_URL + '/upload/chunk'); chunkRequest.setMethod('POST'); chunkRequest.setHeader('X-Api-Key', API_KEY); String boundary = '---------------------------' + String.valueOf(DateTime.now().getTime()); chunkRequest.setHeader('Content-Type', 'multipart/form-data; boundary=' + boundary); String body = ''; body += '--' + boundary + '\r\n'; body += 'Content-Disposition: form-data; name="upload_id"\r\n\r\n'; body += uploadId + '\r\n'; body += '--' + boundary + '\r\n'; body += 'Content-Disposition: form-data; name="chunk_index"\r\n\r\n'; body += String.valueOf(i) + '\r\n'; body += '--' + boundary + '\r\n'; body += 'Content-Disposition: form-data; name="total_chunks"\r\n\r\n'; body += String.valueOf(totalChunks) + '\r\n'; body += '--' + boundary + '\r\n'; body += 'Content-Disposition: form-data; name="chunk"; filename="chunk"\r\n'; body += 'Content-Type: application/octet-stream\r\n\r\n'; String bodyEnd = '\r\n--' + boundary + '--\r\n'; Blob bodyBlob = Blob.valueOf(body); Blob bodyEndBlob = Blob.valueOf(bodyEnd); // Join the blobs Blob fullBody = Blob.valueOf(''); fullBody = Blob.valueOf(EncodingUtil.base64Encode(bodyBlob) + EncodingUtil.base64Encode(chunkBlob) + EncodingUtil.base64Encode(bodyEndBlob)); chunkRequest.setBodyAsBlob(fullBody); HttpResponse chunkResponse = http.send(chunkRequest); if (chunkResponse.getStatusCode() != 200) { throw new AuraHandledException('Failed to upload chunk ' + i + ': ' + chunkResponse.getBody()); } } // Step 3: Finalize upload HttpRequest finalizeRequest = new HttpRequest(); finalizeRequest.setEndpoint(API_URL + '/upload/finalize'); finalizeRequest.setMethod('POST'); finalizeRequest.setHeader('X-Api-Key', API_KEY); finalizeRequest.setHeader('Content-Type', 'application/json'); // Set expiration date Datetime activeToDate = Datetime.now(); activeToDate = activeToDate.addDays(activeDays); String activeTo = activeToDate.format('yyyy-MM-dd HH:mm:ss'); Map finalizeParams = new Map(); finalizeParams.put('upload_id', uploadId); finalizeParams.put('total_chunks', totalChunks); finalizeParams.put('original_file_name', fileName); finalizeParams.put('description', description); finalizeParams.put('message', message); finalizeParams.put('password', password); finalizeParams.put('reference', reference); finalizeParams.put('active_to', activeTo); finalizeRequest.setBody(JSON.serialize(finalizeParams)); HttpResponse finalizeResponse = http.send(finalizeRequest); if (finalizeResponse.getStatusCode() != 201) { throw new AuraHandledException('Failed to finalize upload: ' + finalizeResponse.getBody()); } Map finalResult = (Map) JSON.deserializeUntyped(finalizeResponse.getBody()); Map result = new Map(); result.put('mediaId', (String) finalResult.get('media_id')); result.put('permalink', (String) finalResult.get('permalink')); result.put('shortcode', (String) finalResult.get('shortcode')); return result; } catch (Exception e) { throw new AuraHandledException('Error uploading file: ' + e.getMessage()); } } // Save shared file info to a Salesforce record @AuraEnabled public static void saveSharedFileInfo(Id recordId, String objectName, String mediaId, String permalink) { try { // Create a custom object to store the shared file info SObject sharedFile = Schema.getGlobalDescribe().get('Shared_File__c').newSObject(); sharedFile.put('Media_ID__c', mediaId); sharedFile.put('Permalink__c', permalink); sharedFile.put('Related_Record__c', recordId); sharedFile.put('Object_Type__c', objectName); insert sharedFile; } catch (Exception e) { throw new AuraHandledException('Error saving shared file info: ' + e.getMessage()); } } } ``` ## Document Management Systems ### Integration with DMS Using PHP ```php 'your-api-key-here', 'api_url' => 'https://your-wordpress-site.com/wp-json/qdr-tss/v1', 'watch_folder' => '/path/to/watch/folder', 'processed_folder' => '/path/to/processed/folder', 'log_file' => '/path/to/log/file.log', 'db_host' => 'localhost', 'db_name' => 'dms_database', 'db_user' => 'db_user', 'db_pass' => 'db_password', ]; // Initialize database connection $db = new mysqli($config['db_host'], $config['db_user'], $config['db_pass'], $config['db_name']); if ($db->connect_error) { log_message("Database connection failed: " . $db->connect_error); exit; } // Create the shared_files table if it doesn't exist $db->query(" CREATE TABLE IF NOT EXISTS shared_files ( id INT AUTO_INCREMENT PRIMARY KEY, file_path VARCHAR(255) NOT NULL, original_file_name VARCHAR(255) NOT NULL, media_id VARCHAR(255) NOT NULL, permalink TEXT NOT NULL, shortcode TEXT NOT NULL, password VARCHAR(255) NOT NULL, reference VARCHAR(255), upload_date DATETIME DEFAULT CURRENT_TIMESTAMP, expiry_date DATETIME NOT NULL, document_type VARCHAR(50), document_id VARCHAR(50), notes TEXT ) "); // Get all files in the watch folder $files = glob($config['watch_folder'] . '/*.*'); foreach ($files as $file_path) { $file_name = basename($file_path); log_message("Processing file: " . $file_name); // Get metadata from the file name // Assuming file names follow a pattern like "DOCTYPE_DOCID_REFERENCE.pdf" $file_parts = explode('_', pathinfo($file_name, PATHINFO_FILENAME)); $document_type = isset($file_parts[0]) ? $file_parts[0] : ''; $document_id = isset($file_parts[1]) ? $file_parts[1] : ''; $reference = isset($file_parts[2]) ? $file_parts[2] : ''; // Generate a random password $password = generate_random_password(); try { // Upload the file $result = upload_file( $file_path, "Document: $document_type - $document_id", "This file was automatically uploaded by the DMS integration.", $password, $reference ); // Store the result in the database $stmt = $db->prepare("INSERT INTO shared_files ( file_path, original_file_name, media_id, permalink, shortcode, password, reference, expiry_date, document_type, document_id ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); $expiry_date = date('Y-m-d H:i:s', strtotime('+30 days')); $stmt->bind_param( 'ssssssssss', $file_path, $file_name, $result['media_id'], $result['permalink'], $result['shortcode'], $password, $reference, $expiry_date, $document_type, $document_id ); $stmt->execute(); if ($stmt->affected_rows > 0) { log_message("File uploaded and recorded in the database."); // Move the file to the processed folder $processed_path = $config['processed_folder'] . '/' . $file_name; rename($file_path, $processed_path); log_message("File moved to processed folder."); } else { log_message("Failed to record file in the database."); } $stmt->close(); } catch (Exception $e) { log_message("Error: " . $e->getMessage()); } } $db->close(); /** * Upload a file using the QDR Temporary Shared Storage REST API */ function upload_file($file_path, $description, $message, $password, $reference) { global $config; // File information $file_name = basename($file_path); $file_size = filesize($file_path); $chunk_size = 1024 * 1024; // 1MB chunks $total_chunks = ceil($file_size / $chunk_size); // Step 1: Initialize upload $ch = curl_init($config['api_url'] . '/upload/init'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'X-Api-Key: ' . $config['api_key'], 'Content-Type: application/json' ]); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([ 'original_file_name' => $file_name, 'file_size' => $file_size ])); $response = curl_exec($ch); curl_close($ch); $init_result = json_decode($response, true); if (!isset($init_result['upload_id'])) { throw new Exception('Failed to initialize upload: ' . $response); } $upload_id = $init_result['upload_id']; // Step 2: Upload chunks $file = fopen($file_path, 'rb'); for ($i = 0; $i < $total_chunks; $i++) { // Create a temporary file for the chunk $chunk_file = tempnam(sys_get_temp_dir(), 'chunk'); $chunk_handle = fopen($chunk_file, 'wb'); // Read chunk from original file $chunk_data = fread($file, $chunk_size); fwrite($chunk_handle, $chunk_data); fclose($chunk_handle); // Upload the chunk $ch = curl_init($config['api_url'] . '/upload/chunk'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'X-Api-Key: ' . $config['api_key'] ]); $post_data = [ 'upload_id' => $upload_id, 'chunk_index' => $i, 'total_chunks' => $total_chunks, 'chunk' => new CURLFile($chunk_file, 'application/octet-stream', 'chunk') ]; curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); $response = curl_exec($ch); curl_close($ch); // Delete temporary chunk file unlink($chunk_file); $chunk_result = json_decode($response, true); if (!isset($chunk_result['status']) || $chunk_result['status'] !== 'chunk_uploaded') { throw new Exception('Failed to upload chunk ' . $i . ': ' . $response); } log_message("Uploaded chunk " . ($i + 1) . " of " . $total_chunks); } fclose($file); // Step 3: Finalize upload $ch = curl_init($config['api_url'] . '/upload/finalize'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'X-Api-Key: ' . $config['api_key'], 'Content-Type: application/json' ]); // Set expiration to 30 days from now $active_to = date('Y-m-d H:i:s', strtotime('+30 days')); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([ 'upload_id' => $upload_id, 'total_chunks' => $total_chunks, 'original_file_name' => $file_name, 'description' => $description, 'message' => $message, 'password' => $password, 'reference' => $reference, 'active_to' => $active_to ])); $response = curl_exec($ch); curl_close($ch); $final_result = json_decode($response, true); if (!isset($final_result['media_id'])) { throw new Exception('Failed to finalize upload: ' . $response); } return $final_result; } /** * Generate a random password */ function generate_random_password($length = 12) { $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+'; $password = ''; for ($i = 0; $i < $length; $i++) { $password .= $chars[rand(0, strlen($chars) - 1)]; } return $password; } /** * Log a message to the log file */ function log_message($message) { global $config; $date = date('Y-m-d H:i:s'); $log_message = "[$date] $message\n"; file_put_contents($config['log_file'], $log_message, FILE_APPEND); echo $log_message; } ``` ## Email Systems ### Email Integration with PHPMailer ```php isSMTP(); $mail->Host = 'smtp.example.com'; $mail->SMTPAuth = true; $mail->Username = 'user@example.com'; $mail->Password = 'password'; $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; $mail->Port = 587; // Recipients $mail->setFrom('from@example.com', 'Your Company'); $mail->addAddress($to_email, $to_name); $mail->addReplyTo('info@example.com', 'Information'); // Content $mail->isHTML(true); $mail->Subject = $subject; $mail->Body = $body; $mail->AltBody = strip_tags($body); $mail->send(); return true; } catch (Exception $e) { throw new Exception('Message could not be sent. Mailer Error: ' . $mail->ErrorInfo); } } /** * Upload a file using the QDR Temporary Shared Storage REST API */ function upload_file($file_path, $description, $message, $password, $reference) { $api_key = 'your-api-key-here'; $api_url = 'https://your-wordpress-site.com/wp-json/qdr-tss/v1'; // Implement the file upload logic (same as in previous examples) // ... } /** * Generate a random password */ function generate_random_password($length = 12) { $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+'; $password = ''; for ($i = 0; $i < $length; $i++) { $password .= $chars[rand(0, strlen($chars) - 1)]; } return $password; } // Example usage try { $file_path = '/path/to/document.pdf'; $description = 'Important Document'; $message = 'Please review this document and provide feedback.'; $recipient_email = 'client@example.com'; $recipient_name = 'John Doe'; $email_subject = 'Important Document for Review'; $email_body = '

Important Document

Dear {{RECIPIENT_NAME}},

We have shared an important document with you for review.

You can download the document using the following information:

  • Download Link: {{FILE_NAME}}
  • Password: {{PASSWORD}}
  • Reference: {{REFERENCE}}

The link will be active until {{EXPIRY_DATE}}.

If you have any questions, please contact us.

Best regards,
Your Company

'; $email_body = str_replace('{{RECIPIENT_NAME}}', $recipient_name, $email_body); $result = send_file_by_email($file_path, $description, $message, $recipient_email, $recipient_name, $email_subject, $email_body); echo "File uploaded and email sent successfully!\n"; echo "Media ID: " . $result['media_id'] . "\n"; echo "Permalink: " . $result['permalink'] . "\n"; } catch (Exception $e) { echo "Error: " . $e->getMessage() . "\n"; } ``` ## Workflow Automation ### Zapier Integration You can integrate the plugin with Zapier to automate workflows. Here's an example Zapier integration script: ```javascript // Zapier Code for QDR Temporary Shared Storage Integration // When a new file is added to Google Drive (Trigger) const inputData = { fileUrl: inputData.fileUrl, fileName: inputData.fileName, fileId: inputData.fileId, mimeType: inputData.mimeType }; // Download the file content const fileResponse = await fetch(inputData.fileUrl, { method: 'GET', headers: { 'Authorization': `Bearer ${bundle.authData.access_token}` } }); // Get file as buffer const fileBuffer = await fileResponse.buffer(); // Upload file to QDR Temporary Shared Storage const API_KEY = 'your-api-key-here'; const API_URL = 'https://your-wordpress-site.com/wp-json/qdr-tss/v1'; // Step 1: Initialize upload const initResponse = await fetch(`${API_URL}/upload/init`, { method: 'POST', headers: { 'X-Api-Key': API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ original_file_name: inputData.fileName, file_size: fileBuffer.length }) }); const initData = await initResponse.json(); if (!initData.upload_id) { throw new Error('Failed to initialize upload'); } const uploadId = initData.upload_id; // Step 2: Upload chunks const chunkSize = 1024 * 1024; // 1MB chunks const totalChunks = Math.ceil(fileBuffer.length / chunkSize); for (let i = 0; i < totalChunks; i++) { const start = i * chunkSize; const end = Math.min(fileBuffer.length, start + chunkSize); const chunk = fileBuffer.slice(start, end); const formData = new FormData(); formData.append('upload_id', uploadId); formData.append('chunk_index', i); formData.append('total_chunks', totalChunks); formData.append('chunk', new Blob([chunk], { type: 'application/octet-stream' }), 'chunk'); const chunkResponse = await fetch(`${API_URL}/upload/chunk`, { method: 'POST', headers: { 'X-Api-Key': API_KEY }, body: formData }); const chunkData = await chunkResponse.json(); if (!chunkData.status || chunkData.status !== 'chunk_uploaded') { throw new Error(`Failed to upload chunk ${i}`); } } // Step 3: Finalize upload const description = `File uploaded from Google Drive: ${inputData.fileName}`; const message = 'This file was automatically uploaded via Zapier.'; const password = generatePassword(); const reference = `ZAPIER-${Date.now()}`; const activeTo = new Date(); activeTo.setDate(activeTo.getDate() + 30); // 30 days from now const finalizeResponse = await fetch(`${API_URL}/upload/finalize`, { method: 'POST', headers: { 'X-Api-Key': API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ upload_id: uploadId, total_chunks: totalChunks, original_file_name: inputData.fileName, description, message, password, reference, active_to: activeTo.toISOString().slice(0, 19).replace('T', ' ') }) }); const finalizeData = await finalizeResponse.json(); if (!finalizeData.media_id) { throw new Error('Failed to finalize upload'); } // Generate password function function generatePassword(length = 12) { const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+'; let password = ''; for (let i = 0; i < length; i++) { password += chars.charAt(Math.floor(Math.random() * chars.length)); } return password; } // Return data for next Zapier step return { media_id: finalizeData.media_id, permalink: finalizeData.permalink, shortcode: finalizeData.shortcode, password: password, reference: reference, expiry_date: activeTo.toISOString().slice(0, 10) }; ``` ## Conclusion The QDR Temporary Shared Storage plugin's REST API enables integration with a wide variety of applications and systems. By following the examples in this guide, you can easily incorporate secure file sharing capabilities into your existing workflows and applications. For further assistance or custom integration solutions, please contact the plugin author or refer to the API documentation in the plugin's readme file.