Files
tyforum/script/post_attach.pl
2015-01-03 11:43:36 +01:00

314 lines
11 KiB
Perl
Executable File

#!/usr/bin/perl
#------------------------------------------------------------------------------
# mwForum - Web-based discussion forum
# Copyright (c) 1999-2015 Markus Wichitill
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#------------------------------------------------------------------------------
use strict;
use warnings;
no warnings qw(uninitialized redefine);
# Imports
use MwfMain;
#------------------------------------------------------------------------------
# Init
my ($m, $cfg, $lng, $user, $userId) = MwfMain->new($_[0]);
# Get CGI parameters
$m->{ajax} = $m->paramBool('ajax');
my $action = $m->paramStrId('act');
my $postId = $m->paramInt('pid');
my $attachId = $m->paramInt('aid');
my $caption = $m->paramStr('caption');
my $embed = $m->paramBool('embed');
my $change = $m->paramBool('change');
my $delete = $m->paramBool('delete');
my $submitted = $m->paramBool('subm');
$postId or $m->error('errParamMiss') if $action eq 'upload';
$attachId or $m->error('errParamMiss') if $change || $delete;
# Get attachment
my $attach = undef;
if ($attachId) {
$attach = $m->fetchHash("
SELECT * FROM attachments WHERE id = ?", $attachId);
$attach or $m->error('errAttNotFnd');
$postId = $attach->{postId};
}
# Get post
my $post = $m->fetchHash("
SELECT * FROM posts WHERE id = ?", $postId);
$post or $m->error('errPstNotFnd');
my $postIdMod = $postId % 100;
my $boardId = $post->{boardId};
my $topicId = $post->{topicId};
# Get board
my $board = $m->fetchHash("
SELECT * FROM boards WHERE id = ?", $boardId);
# Check if user can see and write to board
my $boardAdmin = $user->{admin} || $m->boardAdmin($userId, $boardId)
|| $board->{topicAdmins} && $m->topicAdmin($userId, $topicId);
$boardAdmin || $m->boardVisible($board) or $m->error('errNoAccess');
$boardAdmin || $m->boardWritable($board, 1) or $m->error('errNoAccess');
# Check if user owns post or is moderator
$userId && $userId == $post->{userId} || $boardAdmin or $m->error('errNoAccess');
# Check if attachments are enabled
$cfg->{attachments} && ($board->{attach} == 1 || $board->{attach} == 2 && $boardAdmin)
or $m->error('errNoAccess');
# Check if topic or post is locked
!$m->fetchArray("
SELECT locked FROM topics WHERE id = ?", $topicId)
|| $boardAdmin or $m->error('errTpcLocked');
!$post->{locked} || $boardAdmin or $m->error('errPstLocked');
# Check authorization
$m->checkAuthz($user, 'attach');
# Disable embed if not allowed
$embed = 0 if !$cfg->{attachImg};
# Process form
if ($submitted) {
# Check request source authentication
$m->checkSourceAuth() or $m->formError('errSrcAuth');
# Process upload form
if ($action eq 'upload') {
# Get upload, check filename and size
my ($upload, $fileName, $fileSize) = $m->getUpload('file');
length($fileName) or $m->error('errAttName');
$fileSize or $m->error('errAttSize');
# Make sure filenames don't clash
my ($name, $ext) = $fileName =~ /(.+?)(\.[^.]+)?\z/;
$name = substr($name, 0, $cfg->{attachNameLen} || 40);
$ext = substr($ext, 0, $cfg->{attachNameLen} || 40);
my $webImage = $ext =~ /^\.(?:jpg|png|gif)\z/i ? 1 : 0;
my $like = $m->{pgsql} ? 'ILIKE' : 'LIKE';
my $num = "";
for my $i (0 .. 100) {
$num = $i ? "-$i" : "";
my $nameExists = $m->fetchArray("
SELECT 1 FROM attachments WHERE postId = ? AND LOWER(fileName) $like LOWER(?)",
$postId, $webImage ? "$name$num%" : "$name$num$ext");
last if !$nameExists;
$i < 100 or $m->formError("Too many filename collisions.");
}
$fileName = "$name$num$ext";
# If there's no error, finish action
if (!@{$m->{formErrors}}) {
# Create directories and attachment file
my $path = "$cfg->{attachFsPath}/$postIdMod";
$m->createDirectories($path, $postId);
$m->saveUpload('file', $upload, "$path/$postId/" . $m->encFsPath($fileName));
# Add attachments table entry
$webImage = 2 if $webImage && $embed;
$caption = substr($caption, 0, 100);
my $captionEsc = $m->escHtml($caption);
$m->dbDo("
INSERT INTO attachments (postId, webImage, fileName, caption) VALUES (?, ?, ?, ?)",
$postId, $webImage, $fileName, $captionEsc);
$attachId = $m->dbInsertId("attachments");
# Resize image
$m->resizeAttachment($attachId) if $webImage && $cfg->{attachImgRsz};
# Log action and finish
$m->logAction(1, 'post', 'attach', $userId, $boardId, $topicId, $postId, $attachId);
if ($m->{ajax}) {
$m->printHttpHeader();
print $m->json({ ok => 1 });
}
else {
$m->redirect('post_attach', pid => $postId, msg => 'PstAttach');
}
}
}
# Process delete all action
elsif ($action eq 'delAll') {
# If there's no error, finish action
if (!@{$m->{formErrors}}) {
# Delete all attachments
my $attachments = $m->fetchAllArray("
SELECT id FROM attachments WHERE postId = ?", $postId);
for my $attachment (@$attachments) {
$m->deleteAttachment($attachment->[0]);
}
# Log action and finish
$m->logAction(1, 'post', 'attdlall', $userId, $boardId, $topicId, $postId);
$m->redirect('post_attach', pid => $postId, msg => 'PstDetach');
}
}
# Process delete form action
elsif ($delete) {
# If there's no error, finish action
if (!@{$m->{formErrors}}) {
# Delete attachment
$m->deleteAttachment($attachId);
# Log action and finish
$m->logAction(1, 'post', 'detach', $userId, $boardId, $topicId, $postId, $attachId);
$m->redirect('post_attach', pid => $postId, msg => 'PstDetach');
}
}
# Process change form action
elsif ($change) {
# If there's no error, finish action
if (!@{$m->{formErrors}}) {
# Update attachment
my $webImage = $attach->{fileName} =~ /\.(?:jpg|png|gif)\z/i ? 1 : 0;
$webImage = 2 if $webImage && $embed;
$caption = substr($caption, 0, 100);
my $captionEsc = $m->escHtml($caption);
$m->dbDo("
UPDATE attachments SET webImage = ?, caption = ? WHERE id = ?",
$webImage, $captionEsc, $attachId);
# Delete thumbnail
if ($webImage && !$embed) {
my $file = "$cfg->{attachFsPath}/$postIdMod/$postId/$attach->{fileName}";
$file =~ s!\.(?:jpg|png|gif)\z!.thb.jpg!i;
unlink $file;
}
# Log action and finish
$m->logAction(1, 'post', 'attchg', $userId, $boardId, $topicId, $postId, $attachId);
$m->redirect('post_attach', pid => $postId, msg => 'PstAttChg');
}
}
else { $m->error('errParamMiss') }
}
# Print AJAX errors or form
if ($m->{ajax} && @{$m->{formErrors}}) {
$m->printHttpHeader();
print $m->json({ error => $m->{formErrors}[0] });
}
elsif (!$submitted || @{$m->{formErrors}}) {
# Print header
$m->printHeader(undef, { postId => $postId, maxAttachLen => $cfg->{maxAttachLen}});
# Get existing attachments
my $attachments = $m->fetchAllHash("
SELECT * FROM attachments WHERE postId = ? ORDER BY id", $postId);
# Print page bar
my @navLinks = ({ url => $m->url('topic_show', pid => $postId), txt => 'comUp', ico => 'up' });
my @userLinks = ();
push @userLinks, { url => $m->url('user_confirm', script => 'post_attach', pid => $postId,
act => 'delAll'), txt => 'attDelAll', ico => 'delete' }
if @$attachments;
$m->printPageBar(mainTitle => $lng->{attTitle}, navLinks => \@navLinks, userLinks => \@userLinks);
# Print hints and form errors
if ($m->paramDefined('msg')) { $m->printHints(['attGoPostT']) }
else { $m->printHints([$lng->{attDropNote}], 'dropNote', 1) }
$m->printFormErrors();
# Prepare values
my $sizeStr = $m->formatSize($cfg->{maxAttachLen});
my $label = $m->formatStr($lng->{attUplFiles}, { size => $sizeStr });
my $embedChk = $cfg->{attachImgDef} ? 'checked' : "";
# Print attachment form
print
"<form id='upload' action='post_attach$m->{ext}' method='post' enctype='multipart/form-data'>\n",
"<div class='frm'>\n",
"<div class='hcl'><span class='htt'>$lng->{attUplTtl}</span></div>\n",
"<div class='ccl' id='dropZone'>\n",
"<fieldset>\n",
"<label class='lbw'>$label\n",
"<input type='file' name='file' autofocus></label>\n",
"<label class='lbw'>$lng->{attUplCapt}\n",
"<input type='text' class='hwi' name='caption' maxlength='100'></label>\n",
"</fieldset>\n";
print
"<fieldset>\n",
"<label><input type='checkbox' name='embed' $embedChk>$lng->{attUplEmbed}</label>\n",
"</fieldset>\n"
if $cfg->{attachImg};
print
$m->submitButton('attUplB', 'attach', 'upload'),
"<input type='hidden' name='pid' value='$postId'>\n",
"<input type='hidden' name='act' value='upload'>\n",
$m->stdFormFields(),
"</div>\n",
"</div>\n",
"</form>\n\n";
# Print existing attachments
for my $attach (@$attachments) {
my $fileName = $attach->{fileName};
print
"<form action='post_attach$m->{ext}' method='post'>\n",
"<div class='frm'>\n",
"<div class='hcl'><span class='htt'>$lng->{attAttTtl}</span> $fileName</div>\n",
"<div class='ccl'>\n";
my $attFile = "$cfg->{attachFsPath}/$postIdMod/$postId/$fileName";
my $attUrl = "$cfg->{attachUrlPath}/$postIdMod/$postId/$fileName";
my $imgShowUrl = $m->url('attach_show', aid => $attach->{id});
my $caption = $attach->{caption};
my $sizeStr = $m->formatSize(-s $m->encFsPath($attFile));
$embedChk = $attach->{webImage} == 2 ? 'checked' : "";
if ($cfg->{attachImg} && $attach->{webImage} == 2 && $user->{showImages}) {
my $thbFile = $attFile;
my $thbUrl = $attUrl;
$thbFile =~ s!\.(?:jpg|png|gif)\z!.thb.jpg!i;
$thbUrl =~ s!\.(?:jpg|png|gif)\z!.thb.jpg!i;
my $title = "title='$sizeStr'";
print $cfg->{attachImgThb} && (-f $m->encFsPath($thbFile) || $m->addThumbnail($attFile))
? "<p><a href='$imgShowUrl'><img class='amt' src='$thbUrl' $title alt=''></a></p>"
: "<p><img class='ami' src='$attUrl' $title alt=''></p>";
}
elsif ($attach->{webImage}) {
print "<p><a href='$imgShowUrl'>$fileName</a> ($sizeStr)</p>";
}
else {
print "<p><a href='$attUrl'>$fileName</a> ($sizeStr)</p>";
}
print
"<label class='lbw'>$lng->{attUplCapt}\n",
"<input type='text' class='hwi' name='caption' maxlength='100' value='$caption'></label>\n",
$cfg->{attachImg} && $attach->{webImage}
? "<div><label><input type='checkbox' name='embed' $embedChk>$lng->{attUplEmbed}</label></div>\n"
: "",
$m->submitButton('attAttChgB', 'edit', 'change'),
$m->submitButton('attAttDelB', 'delete', 'delete'),
"<input type='hidden' name='aid' value='$attach->{id}'>\n",
$m->stdFormFields(),
"</div>\n",
"</div>\n",
"</form>\n\n";
}
# Log action and finish
$m->logAction(3, 'post', 'attach', $userId, $boardId, $topicId, $postId);
$m->printFooter();
}
$m->finish();