Reworking attachment logic in Go, bumping Nginx max file upload size, fixing local dev env, changes to .gitignore
This commit is contained in:
parent
52d50e8b57
commit
a5ccdd8472
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -18,3 +18,6 @@ backups/*
|
||||||
# Go binaries
|
# Go binaries
|
||||||
go/server
|
go/server
|
||||||
go/vault
|
go/vault
|
||||||
|
go/go.mod
|
||||||
|
go/go.sum
|
||||||
|
go/goose.env
|
||||||
|
|
|
||||||
47
Dockerfile.local.php
Normal file
47
Dockerfile.local.php
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
# Use the official PHP 5.6 Apache image for classic mod_php
|
||||||
|
FROM php:5.6-apache
|
||||||
|
|
||||||
|
# Install required system libraries and PHP extensions for CakePHP
|
||||||
|
RUN sed -i 's|http://deb.debian.org/debian|http://archive.debian.org/debian|g' /etc/apt/sources.list && \
|
||||||
|
sed -i 's|http://security.debian.org/debian-security|http://archive.debian.org/debian-security|g' /etc/apt/sources.list && \
|
||||||
|
sed -i '/stretch-updates/d' /etc/apt/sources.list && \
|
||||||
|
echo 'Acquire::AllowInsecureRepositories "true";' > /etc/apt/apt.conf.d/99allow-insecure && \
|
||||||
|
echo 'Acquire::AllowDowngradeToInsecureRepositories "true";' >> /etc/apt/apt.conf.d/99allow-insecure && \
|
||||||
|
apt-get update && \
|
||||||
|
apt-get install --allow-unauthenticated -y libc-client2007e-dev libkrb5-dev libpng-dev libjpeg-dev libfreetype6-dev libcurl4-openssl-dev libxml2-dev libssl-dev libmcrypt-dev libicu-dev && \
|
||||||
|
docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ && \
|
||||||
|
docker-php-ext-configure imap --with-kerberos --with-imap-ssl && \
|
||||||
|
docker-php-ext-install mysqli pdo pdo_mysql mbstring gd curl imap
|
||||||
|
|
||||||
|
# Set environment variables.
|
||||||
|
ENV HOME /root
|
||||||
|
|
||||||
|
# Define working directory.
|
||||||
|
WORKDIR /root
|
||||||
|
|
||||||
|
ARG COMMIT
|
||||||
|
ENV COMMIT_SHA=${COMMIT}
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
# Copy vhost config to Apache's sites-available
|
||||||
|
ADD conf/apache-vhost.conf /etc/apache2/sites-available/cmc-sales.conf
|
||||||
|
ADD conf/ripmime /bin/ripmime
|
||||||
|
|
||||||
|
RUN chmod +x /bin/ripmime \
|
||||||
|
&& a2ensite cmc-sales \
|
||||||
|
&& a2dissite 000-default \
|
||||||
|
&& a2enmod rewrite \
|
||||||
|
&& a2enmod headers
|
||||||
|
|
||||||
|
# Copy site into place.
|
||||||
|
ADD php/ /var/www/cmc-sales
|
||||||
|
ADD php/app/config/database_local.php /var/www/cmc-sales/app/config/database.php
|
||||||
|
RUN mkdir -p /var/www/cmc-sales/app/tmp
|
||||||
|
RUN mkdir -p /var/www/cmc-sales/app/tmp/logs
|
||||||
|
RUN chmod -R 755 /var/www/cmc-sales/app/tmp
|
||||||
|
|
||||||
|
# Ensure CakePHP tmp directory is writable by web server
|
||||||
|
RUN chmod -R 777 /var/www/cmc-sales/app/tmp
|
||||||
|
# By default, simply start apache.
|
||||||
|
CMD /usr/sbin/apache2ctl -D FOREGROUND
|
||||||
|
|
@ -1,9 +1,14 @@
|
||||||
|
resolver 127.0.0.11 valid=10s;
|
||||||
|
|
||||||
server {
|
server {
|
||||||
server_name cmclocal;
|
server_name cmclocal;
|
||||||
auth_basic_user_file /etc/nginx/userpasswd;
|
auth_basic_user_file /etc/nginx/userpasswd;
|
||||||
auth_basic "Restricted";
|
auth_basic "Restricted";
|
||||||
|
client_max_body_size 200M;
|
||||||
|
|
||||||
location /go/ {
|
location /go/ {
|
||||||
proxy_pass http://cmc-go:8080;
|
set $upstream_go cmc-go:8080;
|
||||||
|
proxy_pass http://$upstream_go;
|
||||||
proxy_read_timeout 300s;
|
proxy_read_timeout 300s;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
|
@ -11,7 +16,8 @@ server {
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
}
|
}
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://cmc-php:80;
|
set $upstream_php cmc-php:80;
|
||||||
|
proxy_pass http://$upstream_php;
|
||||||
proxy_read_timeout 300s;
|
proxy_read_timeout 300s;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ server {
|
||||||
server_name cmclocal;
|
server_name cmclocal;
|
||||||
auth_basic_user_file /etc/nginx/userpasswd;
|
auth_basic_user_file /etc/nginx/userpasswd;
|
||||||
auth_basic "Restricted";
|
auth_basic "Restricted";
|
||||||
|
client_max_body_size 200M;
|
||||||
location /go/ {
|
location /go/ {
|
||||||
proxy_pass http://cmc-prod-go:8082;
|
proxy_pass http://cmc-prod-go:8082;
|
||||||
proxy_read_timeout 300s;
|
proxy_read_timeout 300s;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ server {
|
||||||
server_name cmclocal;
|
server_name cmclocal;
|
||||||
auth_basic_user_file /etc/nginx/userpasswd;
|
auth_basic_user_file /etc/nginx/userpasswd;
|
||||||
auth_basic "Restricted";
|
auth_basic "Restricted";
|
||||||
|
client_max_body_size 200M;
|
||||||
location /go/ {
|
location /go/ {
|
||||||
proxy_pass http://cmc-stg-go:8082;
|
proxy_pass http://cmc-stg-go:8082;
|
||||||
proxy_read_timeout 300s;
|
proxy_read_timeout 300s;
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ services:
|
||||||
DB_USER: cmc
|
DB_USER: cmc
|
||||||
DB_PASSWORD: xVRQI&cA?7AU=hqJ!%au
|
DB_PASSWORD: xVRQI&cA?7AU=hqJ!%au
|
||||||
DB_NAME: cmc
|
DB_NAME: cmc
|
||||||
|
GO_APP_HOST: cmc-prod-go:8082
|
||||||
volumes:
|
volumes:
|
||||||
- /home/cmc/files/pdf:/var/www/cmc-sales/app/webroot/pdf
|
- /home/cmc/files/pdf:/var/www/cmc-sales/app/webroot/pdf
|
||||||
- /home/cmc/files/attachments_files:/var/www/cmc-sales/app/webroot/attachments_files
|
- /home/cmc/files/attachments_files:/var/www/cmc-sales/app/webroot/attachments_files
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ services:
|
||||||
DB_USER: cmc
|
DB_USER: cmc
|
||||||
DB_PASSWORD: xVRQI&cA?7AU=hqJ!%au
|
DB_PASSWORD: xVRQI&cA?7AU=hqJ!%au
|
||||||
DB_NAME: cmc
|
DB_NAME: cmc
|
||||||
|
GO_APP_HOST: cmc-stg-go:8082
|
||||||
volumes:
|
volumes:
|
||||||
- /home/cmc/files/pdf:/var/www/cmc-sales/app/webroot/pdf
|
- /home/cmc/files/pdf:/var/www/cmc-sales/app/webroot/pdf
|
||||||
- /home/cmc/files/attachments_files:/var/www/cmc-sales/app/webroot/attachments_files
|
- /home/cmc/files/attachments_files:/var/www/cmc-sales/app/webroot/attachments_files
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,10 @@ services:
|
||||||
- ./conf/nginx-site.conf:/etc/nginx/conf.d/cmc.conf
|
- ./conf/nginx-site.conf:/etc/nginx/conf.d/cmc.conf
|
||||||
- ./userpasswd:/etc/nginx/userpasswd:ro
|
- ./userpasswd:/etc/nginx/userpasswd:ro
|
||||||
depends_on:
|
depends_on:
|
||||||
- cmc-php
|
cmc-php:
|
||||||
|
condition: service_started
|
||||||
|
cmc-go:
|
||||||
|
condition: service_started
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
networks:
|
networks:
|
||||||
- cmc-network
|
- cmc-network
|
||||||
|
|
@ -16,9 +19,11 @@ services:
|
||||||
cmc-php:
|
cmc-php:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile.stg.php
|
dockerfile: Dockerfile.local.php
|
||||||
platform: linux/amd64
|
platform: linux/amd64
|
||||||
container_name: cmc-php
|
container_name: cmc-php
|
||||||
|
environment:
|
||||||
|
GO_APP_HOST: cmc-go:8080
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
volumes:
|
volumes:
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
"code.springupsoftware.com/cmc/cmc-sales/internal/cmc/db"
|
"code.springupsoftware.com/cmc/cmc-sales/internal/cmc/db"
|
||||||
"code.springupsoftware.com/cmc/cmc-sales/internal/cmc/email"
|
"code.springupsoftware.com/cmc/cmc-sales/internal/cmc/email"
|
||||||
|
"code.springupsoftware.com/cmc/cmc-sales/internal/cmc/handlers/attachments"
|
||||||
quotes "code.springupsoftware.com/cmc/cmc-sales/internal/cmc/handlers/quotes"
|
quotes "code.springupsoftware.com/cmc/cmc-sales/internal/cmc/handlers/quotes"
|
||||||
"code.springupsoftware.com/cmc/cmc-sales/internal/cmc/templates"
|
"code.springupsoftware.com/cmc/cmc-sales/internal/cmc/templates"
|
||||||
"github.com/go-co-op/gocron"
|
"github.com/go-co-op/gocron"
|
||||||
|
|
@ -60,6 +61,7 @@ func main() {
|
||||||
|
|
||||||
// Load handlers
|
// Load handlers
|
||||||
quoteHandler := quotes.NewQuotesHandler(queries, tmpl, emailService)
|
quoteHandler := quotes.NewQuotesHandler(queries, tmpl, emailService)
|
||||||
|
attachmentHandler := attachments.NewAttachmentHandler(queries)
|
||||||
|
|
||||||
// Setup routes
|
// Setup routes
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
|
|
@ -77,6 +79,11 @@ func main() {
|
||||||
goRouter.HandleFunc("/quotes/disable-reminders", quoteHandler.DisableReminders).Methods("POST")
|
goRouter.HandleFunc("/quotes/disable-reminders", quoteHandler.DisableReminders).Methods("POST")
|
||||||
goRouter.HandleFunc("/quotes/enable-reminders", quoteHandler.EnableReminders).Methods("POST")
|
goRouter.HandleFunc("/quotes/enable-reminders", quoteHandler.EnableReminders).Methods("POST")
|
||||||
|
|
||||||
|
// Attachment routes
|
||||||
|
goRouter.HandleFunc("/attachments/upload", attachmentHandler.Create).Methods("POST")
|
||||||
|
goRouter.HandleFunc("/attachments/{id}", attachmentHandler.Get).Methods("GET")
|
||||||
|
goRouter.HandleFunc("/attachments/{id}", attachmentHandler.Delete).Methods("DELETE")
|
||||||
|
|
||||||
// The following routes are currently disabled:
|
// The following routes are currently disabled:
|
||||||
/*
|
/*
|
||||||
// API routes
|
// API routes
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package handlers
|
package attachments
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
@ -111,18 +111,22 @@ func (h *AttachmentHandler) Create(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get file from form
|
// Get file from form - try both field names (CakePHP format and plain)
|
||||||
file, handler, err := r.FormFile("file")
|
file, handler, err := r.FormFile("data[Attachment][file]")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "No file uploaded", http.StatusBadRequest)
|
// Try plain "file" field name as fallback
|
||||||
return
|
file, handler, err = r.FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "No file uploaded", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
// Generate unique filename
|
// Generate unique filename
|
||||||
ext := filepath.Ext(handler.Filename)
|
ext := filepath.Ext(handler.Filename)
|
||||||
filename := fmt.Sprintf("%d_%s%s", time.Now().Unix(), handler.Filename[:len(handler.Filename)-len(ext)], ext)
|
filename := fmt.Sprintf("%d_%s%s", time.Now().Unix(), handler.Filename[:len(handler.Filename)-len(ext)], ext)
|
||||||
|
|
||||||
// Create attachments directory if it doesn't exist
|
// Create attachments directory if it doesn't exist
|
||||||
attachDir := "webroot/attachments_files"
|
attachDir := "webroot/attachments_files"
|
||||||
if err := os.MkdirAll(attachDir, 0755); err != nil {
|
if err := os.MkdirAll(attachDir, 0755); err != nil {
|
||||||
|
|
@ -131,8 +135,8 @@ func (h *AttachmentHandler) Create(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save file to disk
|
// Save file to disk
|
||||||
filepath := filepath.Join(attachDir, filename)
|
filePath := filepath.Join(attachDir, filename)
|
||||||
dst, err := os.Create(filepath)
|
dst, err := os.Create(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Failed to save file", http.StatusInternalServerError)
|
http.Error(w, "Failed to save file", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
|
@ -144,23 +148,38 @@ func (h *AttachmentHandler) Create(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse principle_id
|
// Parse principle_id - try CakePHP format first, then fallback
|
||||||
principleID := 1 // Default
|
principleID := 1 // Default
|
||||||
if pid := r.FormValue("principle_id"); pid != "" {
|
pid := r.FormValue("data[Attachment][principle_id]")
|
||||||
|
if pid == "" {
|
||||||
|
pid = r.FormValue("principle_id")
|
||||||
|
}
|
||||||
|
if pid != "" {
|
||||||
if id, err := strconv.Atoi(pid); err == nil {
|
if id, err := strconv.Atoi(pid); err == nil {
|
||||||
principleID = id
|
principleID = id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get other form values - try CakePHP format first, then fallback
|
||||||
|
name := r.FormValue("data[Attachment][name]")
|
||||||
|
if name == "" {
|
||||||
|
name = r.FormValue("name")
|
||||||
|
}
|
||||||
|
|
||||||
|
description := r.FormValue("data[Attachment][description]")
|
||||||
|
if description == "" {
|
||||||
|
description = r.FormValue("description")
|
||||||
|
}
|
||||||
|
|
||||||
// Create database record
|
// Create database record
|
||||||
params := db.CreateAttachmentParams{
|
params := db.CreateAttachmentParams{
|
||||||
PrincipleID: int32(principleID),
|
PrincipleID: int32(principleID),
|
||||||
Name: r.FormValue("name"),
|
Name: name,
|
||||||
Filename: handler.Filename,
|
Filename: handler.Filename,
|
||||||
File: filename,
|
File: filePath, // Store full path for PHP compatibility
|
||||||
Type: handler.Header.Get("Content-Type"),
|
Type: handler.Header.Get("Content-Type"),
|
||||||
Size: int32(handler.Size),
|
Size: int32(handler.Size),
|
||||||
Description: r.FormValue("description"),
|
Description: description,
|
||||||
}
|
}
|
||||||
|
|
||||||
if params.Name == "" {
|
if params.Name == "" {
|
||||||
|
|
@ -170,7 +189,7 @@ func (h *AttachmentHandler) Create(w http.ResponseWriter, r *http.Request) {
|
||||||
result, err := h.queries.CreateAttachment(r.Context(), params)
|
result, err := h.queries.CreateAttachment(r.Context(), params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Clean up file on error
|
// Clean up file on error
|
||||||
os.Remove(filepath)
|
os.Remove(filePath)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -216,13 +235,13 @@ func (h *AttachmentHandler) Update(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
params = db.UpdateAttachmentParams{
|
params = db.UpdateAttachmentParams{
|
||||||
Name: r.FormValue("name"),
|
Name: r.FormValue("name"),
|
||||||
Description: r.FormValue("description"),
|
Description: r.FormValue("description"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
params.ID = int32(id)
|
params.ID = int32(id)
|
||||||
|
|
||||||
if err := h.queries.UpdateAttachment(r.Context(), params); err != nil {
|
if err := h.queries.UpdateAttachment(r.Context(), params); err != nil {
|
||||||
|
|
@ -248,4 +267,4 @@ func (h *AttachmentHandler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
}
|
}
|
||||||
37
go/internal/cmc/handlers/attachments/attachments_test.go
Normal file
37
go/internal/cmc/handlers/attachments/attachments_test.go
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
package attachments
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.springupsoftware.com/cmc/cmc-sales/internal/cmc/db"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestNewAttachmentHandler tests that the handler is created correctly
|
||||||
|
func TestNewAttachmentHandler(t *testing.T) {
|
||||||
|
queries := &db.Queries{}
|
||||||
|
handler := NewAttachmentHandler(queries)
|
||||||
|
|
||||||
|
if handler == nil {
|
||||||
|
t.Fatal("Expected handler to be created, got nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if handler.queries != queries {
|
||||||
|
t.Fatal("Expected handler.queries to match input queries")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: Full integration tests with database mocking would require more setup.
|
||||||
|
// For now, this provides basic structure validation.
|
||||||
|
// To run full tests, you would need to:
|
||||||
|
// 1. Create a test database or use an in-memory SQLite database
|
||||||
|
// 2. Run migrations
|
||||||
|
// 3. Test each handler method with actual database calls
|
||||||
|
//
|
||||||
|
// Example test structure for future expansion:
|
||||||
|
// func TestListAttachments(t *testing.T) {
|
||||||
|
// db := setupTestDB(t)
|
||||||
|
// defer db.Close()
|
||||||
|
// queries := db.New(db)
|
||||||
|
// handler := NewAttachmentHandler(queries)
|
||||||
|
// // ... test implementation
|
||||||
|
// }
|
||||||
14
php/app/config/database_local.php
Normal file
14
php/app/config/database_local.php
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class DATABASE_CONFIG {
|
||||||
|
|
||||||
|
var $default = array(
|
||||||
|
'driver' => 'mysqli',
|
||||||
|
'persistent' => false,
|
||||||
|
'host' => 'db',
|
||||||
|
'login' => 'cmc',
|
||||||
|
'password' => 'xVRQI&cA?7AU=hqJ!%au',
|
||||||
|
'database' => 'cmc',
|
||||||
|
'prefix' => '',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -39,20 +39,83 @@ class AttachmentsController extends AppController {
|
||||||
|
|
||||||
function add() {
|
function add() {
|
||||||
if (!empty($this->data)) {
|
if (!empty($this->data)) {
|
||||||
|
|
||||||
$attachment = $this->Attachment->process_attachment($this->data);
|
// Check if file was uploaded
|
||||||
if(!$attachment) {
|
if (empty($this->data['Attachment']['file']['tmp_name'])) {
|
||||||
$this->Session->setFlash('The Attachment could not be saved. The filename exists');
|
$error = 'No file uploaded';
|
||||||
}
|
if (isset($this->data['Attachment']['file']['error'])) {
|
||||||
else {
|
$errorCodes = array(
|
||||||
$this->Attachment->create();
|
UPLOAD_ERR_INI_SIZE => 'File exceeds upload_max_filesize',
|
||||||
|
UPLOAD_ERR_FORM_SIZE => 'File exceeds MAX_FILE_SIZE',
|
||||||
if ($this->Attachment->save($attachment)) {
|
UPLOAD_ERR_PARTIAL => 'File only partially uploaded',
|
||||||
$this->Session->setFlash(__('The Attachment has been saved', true));
|
UPLOAD_ERR_NO_FILE => 'No file was uploaded',
|
||||||
$this->redirect(array('action'=>'index'));
|
UPLOAD_ERR_NO_TMP_DIR => 'Missing temporary folder',
|
||||||
} else {
|
UPLOAD_ERR_CANT_WRITE => 'Failed to write file to disk',
|
||||||
$this->Session->setFlash(__('The Attachment could not be saved. Please, try again.', true));
|
UPLOAD_ERR_EXTENSION => 'File upload stopped by extension',
|
||||||
|
);
|
||||||
|
$errorCode = $this->data['Attachment']['file']['error'];
|
||||||
|
$error = isset($errorCodes[$errorCode]) ? $errorCodes[$errorCode] : 'Unknown error: ' . $errorCode;
|
||||||
}
|
}
|
||||||
|
$this->Session->setFlash(__('File upload error: ' . $error, true));
|
||||||
|
$principles = $this->Attachment->Principle->find('list');
|
||||||
|
$this->set(compact('products', 'principles'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proxy the upload request to the Go application
|
||||||
|
$goHost = getenv('GO_APP_HOST');
|
||||||
|
$goUrl = 'http://' . $goHost . '/go/attachments/upload';
|
||||||
|
|
||||||
|
// Prepare the multipart form data for the Go app
|
||||||
|
$postFields = array();
|
||||||
|
|
||||||
|
$postFields['file'] = new CURLFile(
|
||||||
|
$this->data['Attachment']['file']['tmp_name'],
|
||||||
|
$this->data['Attachment']['file']['type'],
|
||||||
|
$this->data['Attachment']['file']['name']
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!empty($this->data['Attachment']['name'])) {
|
||||||
|
$postFields['name'] = $this->data['Attachment']['name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->data['Attachment']['description'])) {
|
||||||
|
$postFields['description'] = $this->data['Attachment']['description'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->data['Attachment']['principle_id'])) {
|
||||||
|
$postFields['principle_id'] = $this->data['Attachment']['principle_id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the request to Go app
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $goUrl);
|
||||||
|
curl_setopt($ch, CURLOPT_POST, 1);
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
|
||||||
|
'Accept: application/json'
|
||||||
|
));
|
||||||
|
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
$curlError = curl_error($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($httpCode == 201) {
|
||||||
|
$this->Session->setFlash(__('The Attachment has been saved', true));
|
||||||
|
$this->redirect(array('action'=>'index'));
|
||||||
|
} else {
|
||||||
|
$errorMsg = 'The Attachment could not be saved.';
|
||||||
|
if ($curlError) {
|
||||||
|
$errorMsg .= ' cURL Error: ' . $curlError;
|
||||||
|
} elseif ($response) {
|
||||||
|
$errorMsg .= ' Response: ' . $response;
|
||||||
|
} else {
|
||||||
|
$errorMsg .= ' HTTP Code: ' . $httpCode;
|
||||||
|
}
|
||||||
|
error_log('Attachment upload failed: ' . $errorMsg);
|
||||||
|
$this->Session->setFlash(__($errorMsg, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$principles = $this->Attachment->Principle->find('list');
|
$principles = $this->Attachment->Principle->find('list');
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<div class="attachments form">
|
<div class="attachments form">
|
||||||
<?php echo $form->create('Attachment', array('type'=>'file'));?>
|
<?php echo $form->create('Attachment', array('type'=>'file', 'url' => array('controller' => 'attachments', 'action' => 'add')));?>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend><?php __('Add Attachment');?></legend>
|
<legend><?php __('Add Attachment');?></legend>
|
||||||
<?php
|
<?php
|
||||||
|
|
@ -7,8 +7,36 @@
|
||||||
echo $form->input('name');
|
echo $form->input('name');
|
||||||
echo $form->file('file');
|
echo $form->file('file');
|
||||||
echo $form->input('description');
|
echo $form->input('description');
|
||||||
echo $form->input('archived');
|
// archived not needed for new uploads
|
||||||
?>
|
?>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<?php echo $form->end('Submit');?>
|
<?php echo $form->end('Submit');?>
|
||||||
</div>
|
</div>
|
||||||
|
<script>
|
||||||
|
// Redirect back to attachments index on successful upload
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('#AttachmentAddForm').submit(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
|
||||||
|
var formData = new FormData(this);
|
||||||
|
$.ajax({
|
||||||
|
url: '/go/attachments/upload',
|
||||||
|
type: 'POST',
|
||||||
|
data: formData,
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
success: function(response) {
|
||||||
|
alert('Attachment uploaded successfully');
|
||||||
|
window.location.href = '/attachments';
|
||||||
|
},
|
||||||
|
error: function(xhr) {
|
||||||
|
alert('Upload failed: ' + (xhr.responseText || 'Unknown error'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue