winix/winixd/plugins/ticket/ticketinfo.cpp

667 lines
15 KiB
C++

/*
* This file is a part of Winix
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2010-2021, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <algorithm>
#include <ctime>
#include "ticketinfo.h"
#include "core/error.h"
#include "core/log.h"
#include "core/misc.h"
#include "pluginmsg.h"
#include "sessiondata.h"
#include "convert/text.h"
namespace Winix
{
namespace Ticket
{
TicketInfo::TicketInfo()
{
Clear();
}
void TicketInfo::SetTDb(TDb * ptdb)
{
tdb = ptdb;
}
void TicketInfo::SetDb(Db * pdb)
{
db = pdb;
}
//void TicketInfo::SetConfig(Config * pconfig)
//{
// config = pconfig;
//}
void TicketInfo::SetSystem(System * psystem)
{
system = psystem;
}
void TicketInfo::SetCur(Cur * pcur)
{
cur = pcur;
}
void TicketInfo::SetFunctions(Functions * pfunctions)
{
functions = pfunctions;
}
void TicketInfo::Clear()
{
ticket = &ticket_empty;
item = &item_empty;
ticket->Clear();
item->Clear();
// we use meta from item which should not be const
cur_conf_wrap = &cur_conf_wrap_empty;
cur_conf = &cur_conf_empty;
cur_conf->clear();
item_tab.clear();
ticket_tab.clear();
item_sort_tab.clear();
create_new_ticket = false;
}
void TicketInfo::MarkAllConfToDelete()
{
ConfTab::iterator i = conf_tab.begin();
for( ; i!=conf_tab.end() ; ++i)
i->second.to_delete = true;
}
void TicketInfo::DeleteAllMarkedConf()
{
ConfTab::iterator inext;
ConfTab::iterator i = conf_tab.begin();
while( i != conf_tab.end() )
{
inext = i;
++inext;
if( i->second.to_delete )
{
log << log3 << "Ticket: deleting ticket conf for dir id: " << i->first << logend;
conf_tab.erase(i);
}
i = inext;
}
}
bool TicketInfo::GetConfContent(const std::wstring & path)
{
int status = system->FollowAllLinks(path, config_dir_tab, config_file, false, false, false);
if( status != 1 )
{
log << log1 << "Ticket: problem with reading a config file: " << path << ", status: " << status << logend;
return false;
}
return true;
}
bool TicketInfo::ParseTicketConf(long mount_dir_id, const std::wstring & path)
{
log << log3 << "Ticket: parsing conf file: " << path << logend;
conf_tab[mount_dir_id].file_name = path;
pt::Space & space = conf_tab[mount_dir_id].conf;
return (conf_parser.parse_space(config_file.item_content.content_raw, space) == pt::SpaceParser::ok);
}
void TicketInfo::ReadTicketConf(const Mount & mount, bool skip_existing_configs)
{
if( mount.param[mount_par_ticket_conf].defined &&
mount.param[mount_par_ticket_conf].arg.size() == 1 )
{
const std::wstring & file_name = mount.param[mount_par_ticket_conf].arg[0];
ConfTab::iterator c = conf_tab.find(mount.dir_id);
bool exists = (c != conf_tab.end() && c->second.file_name == file_name);
if( exists )
c->second.to_delete = false;
if( !(skip_existing_configs && exists) )
{
if( GetConfContent(file_name) )
{
if( !ParseTicketConf(mount.dir_id, file_name) )
conf_tab[mount.dir_id].to_delete = true;
}
else
{
if( exists )
c->second.to_delete = true;
}
}
}
}
// if skip_existing_configs is true then only new config files will be parsed
void TicketInfo::ReadTicketConf(Mounts & mounts, bool skip_existing_configs)
{
Mounts::MountTab::const_iterator i;
const Mounts::MountTab * mtab = mounts.GetMountTab();
// loop through all mount points
for(i=mtab->begin() ; i!=mtab->end() ; ++i)
{
const Mount & mount = i->second;
ReadTicketConf(mount, skip_existing_configs);
}
}
// if skip_existing_configs is true then only new config files will be parsed
void TicketInfo::ReadTicketConf(bool skip_existing_configs)
{
MarkAllConfToDelete();
ReadTicketConf(system->mounts, skip_existing_configs);
DeleteAllMarkedConf();
}
void TicketInfo::FindCurrentConf(long dir_id)
{
Mount * mount = system->mounts.CalcMount(dir_id);
if( mount )
{
// long dir_id = cur->mount->dir_id;
ConfTab::iterator i = conf_tab.find(mount->dir_id);
if( i != conf_tab.end() )
{
cur_conf_wrap = &i->second;
cur_conf = &i->second.conf;
}
else
{
log << log1 << "Ticket: there is no a ticket_conf parameter in the mount point (an empty config used)" << logend;
}
}
else
{
log << log1 << "Ticket: I cannot find the mount point for dir id: " << dir_id << logend;
}
}
void TicketInfo::FindCurrentConf()
{
if( !cur->request->dir_tab.empty() )
FindCurrentConf(cur->request->dir_tab.back()->id);
}
void TicketInfo::CheckMinMaxValue(pt::Space & space, Ticket::TicketParam & par)
{
std::wstring * type = space.get_wstr(L"type");
if( !type )
return;
if( *type == L"integer" )
{
std::wstring * min_str = space.get_wstr(L"min");
std::wstring * max_str = space.get_wstr(L"min");
if( min_str )
{
long minv = Tol(*min_str);
if( par.intv < minv )
par.intv = minv;
}
if( max_str )
{
long maxv = Tol(*max_str);
if( par.intv > maxv )
par.intv = maxv;
}
}
else
if( *type == L"progress" )
{
// !! dodac tez min/max
if( par.intv < 0 )
par.intv = 0;
if( par.intv > 100 )
par.intv = 100;
}
else
if( *type == L"select" )
{
pt::Space::TableType * child_table = space.get_table(L"options"); // CHECKME it was space.find_child_space_table();
if( child_table )
{
for(pt::Space * sp : *child_table)
{
if( sp->to_long(L"id") == par.intv )
{
return;
}
}
}
par.intv = 0;
std::wstring * def = space.get_wstr(L"default");
if( def )
par.intv = Tol(*def);
}
}
pt::Space & TicketInfo::FindAddMetaByParam(pt::Space & meta, long param)
{
pt::Space * params = meta.get_space(L"params"); // CHECKME it was meta.find_child_space_table();
if( params && params->is_table() )
{
for(pt::Space * sp : *params->get_table() )
{
if( sp->to_long(L"id") == param )
{
return *sp;
}
}
}
else
if( !params )
{
params = &meta.add_empty_space(L"params");
}
pt::Space & sp = params->add_empty_space();
sp.add(L"id", param);
return sp;
}
bool TicketInfo::ReadTicketValue(pt::Space & config_param, long param_id, Ticket::TicketParam & par, const std::wstring & value, pt::Space & meta)
{
if( config_param.is_equal(L"type", L"integer") ||
config_param.is_equal(L"type", L"progress") ||
config_param.is_equal(L"type", L"select") )
{
par.intv = Tol(value);
par.decv.clear();
CheckMinMaxValue(config_param, par);
return true;
}
else
if( config_param.is_equal(L"type", L"string") ||
config_param.is_equal(L"type", L"multistring") )
{
// !! dodac cos co sprawdzi czy string nie zawiera znakow konca linii
pt::Space & sp = FindAddMetaByParam(meta, param_id);
sp.add(L"value", value);
return false;
}
if( config_param.is_equal(L"type", L"images") ||
config_param.is_equal(L"type", L"files") )
{
if( !value.empty() )
{
log << log1 << "Ticket: images or files should be added only by a specific html tag (ignored)" << logend;
}
else
{
// an empty field from the html form (ignoring)
}
return false;
}
else
{
// !! dodac obsluge komunikatow
// niech zostanie wyslany komunikat o dodawaniu nieznanego parametru
// i jesli nic nie odpowie na ten komunikat to wtedy zglaszamy blad
log << log1 << "Ticket: incorrect parameter, param: " << par.param << ", value: " << value << " (ignored)" << logend;
}
return false;
}
void TicketInfo::ReadTicketValue(pt::Space & config_param,
long param_id,
const PostFile & value,
pt::Space & meta,
Item & upload_dir)
{
file.Clear(); // clearing and setting date
file.parent_id = upload_dir.id;
file.type = Item::file;
file.item_content.privileges = system->NewFilePrivileges();
file.item_content.file_type = SelectFileType(value.filename);
file.url = value.filename;
functions->PrepareUrl(file);
functions->SetUser(file);
functions->fun_upload.UploadFile(file, value.tmp_filename);
if( cur->request->status == WINIX_ERR_OK )
{
pt::Space & meta_param = FindAddMetaByParam(meta, param_id);
pt::Space & meta_files = meta_param.get_add_space(L"files");
pt::Space & file_space = meta_files.add_empty_space();
if( file.item_content.file_type == WINIX_ITEM_FILETYPE_IMAGE )
file_space.add(L"type", L"image");
else
file_space.add(L"type", L"file");
file_space.add(L"itemid", file.id);
system->MakePath(file, file_path);
file_space.add(L"path", file_path);
}
else
{
log << log1 << "Ticket: problem with uploading" << logend;
}
}
void TicketInfo::ReadTicketValue(pt::Space & space,
long param_id, const PostFile & value, pt::Space & meta)
{
std::wstring * type = space.get_wstr(L"type");
if( type && (*type == L"images" || *type == L"files") )
{
std::wstring * upload_path = space.get_wstr(L"upload_dir");
if( upload_path && !upload_path->empty() )
{
Item * upload_dir = system->dirs.GetDir(*upload_path);
if( upload_dir )
ReadTicketValue(space, param_id, value, meta, *upload_dir);
else
log << log1 << "Ticket: there is no an upload directory: " << upload_path << logend;
}
else
{
log << log1 << "Ticket: you must set 'upload_dir' directory in the config" << logend;
}
}
}
// adding a new parameter only if it not exists in ticket.par_tab
void TicketInfo::ReadTicketParam(pt::Space & config_param, Ticket & ticket, long param_id, const std::wstring & value, pt::Space & meta)
{
ticket_param.param = param_id;
for(size_t i2=0 ; i2<ticket.par_tab.size() ; ++i2)
{
if( ticket.par_tab[i2].param == param_id )
{
// parameter param_id already exists in ticket.par_tab
// (overwritting)
if( ReadTicketValue(config_param, param_id, ticket_param, value, meta) )
ticket.par_tab[i2] = ticket_param;
return;
}
}
// adding a new parameter param_id
if( ReadTicketValue(config_param, param_id, ticket_param, value, meta) )
ticket.par_tab.push_back(ticket_param);
}
void TicketInfo::ReadTicketParam(Ticket & ticket, long param_id, const std::wstring & value, pt::Space & meta)
{
ticket_param.Clear();
pt::Space::TableType * params = cur_conf->get_table(L"params");
if( params )
{
for(pt::Space * space : *params)
{
if( space->to_long(L"id") == param_id )
{
ReadTicketParam(*space, ticket, param_id, value, meta);
return;
}
}
}
log << log1 << "Ticket: skipped incorrect parameter: " << param_id << " (not defined in the config)" << logend;
}
// always adds a new parameter
void TicketInfo::ReadTicketParam(long param_id, const PostFile & value, pt::Space & meta)
{
pt::Space::TableType * child_table = cur_conf->get_table(L"params"); // CHECKME it was cur_conf->find_child_space_table();
if( child_table )
{
for(pt::Space * sp : *child_table)
{
if( sp->to_long(L"id") == param_id )
{
ReadTicketValue(*sp, param_id, value, meta);
return;
}
}
}
log << log1 << "Ticket: skipped incorrect parameter: " << param_id << " (not defined in the config)" << logend;
}
bool TicketInfo::DeleteTicketFile(Ticket & ticket, long file_id, pt::Space & meta)
{
pt::Space::TableType * params = meta.get_table(L"params");
if( params )
{
for(pt::Space * param : *params)
{
pt::Space * files_space = param->get_space(L"files");
if( files_space && files_space->is_table() )
{
pt::Space::TableType * files = files_space->get_table();
for(size_t f=0 ; f < files->size() ; ++f)
{
pt::Space * file = (*files)[f];
if( file->to_long(L"itemid") == file_id )
{
files_space->remove(f);
// !! IMPROVE ME
// temporarily we delete the file here
// but it should be really deleted when the user will press
// the submit button
//functions->fun_rm.RemoveFileOrSymlink(file_id, true);
return true;
}
}
}
}
}
return false;
}
void TicketInfo::ReadTicketParams(Ticket & ticket, bool clear_ticket, pt::Space & meta, bool & file_was_deleted)
{
PostTab::iterator i;
PostFileTab::iterator i2;
file_was_deleted = false;
if( clear_ticket )
ticket.Clear();
// !! IMPROVE ME move me somewhere
std::wstring ticket_delete_prefix = L"ticketdeletefile_";
for(i=cur->request->post_tab.begin() ; i!=cur->request->post_tab.end() ; ++i)
{
// !! CHECKME why ticket_form_prefix is in the global config?
// (this is a plugin variable)
if( pt::is_substr(config->ticket_form_prefix, i->first) )
{
long param_id = Tol(i->first.c_str() + config->ticket_form_prefix.size());
ReadTicketParam(ticket, param_id, i->second, meta);
}
if( pt::is_substr(ticket_delete_prefix, i->first) )
{
long file_id = Tol(i->first.c_str() + ticket_delete_prefix.size());
if( DeleteTicketFile(ticket, file_id, meta) )
{
file_was_deleted = true;
}
}
}
for(i2=cur->request->post_file_tab.begin() ; i2!=cur->request->post_file_tab.end() ; ++i2)
{
if( pt::is_substr(config->ticket_form_prefix, i2->first) )
ReadTicketParam(Tol(i2->first.c_str() + config->ticket_form_prefix.size()), i2->second, meta);
}
ticket.SortParTab();
}
void TicketInfo::RemoveTicket(long file_id)
{
/*
* IMPROVEME
* we should also remove some files (images) for a ticket
* may when 'rm' function is displayed we should show some checkboxes
* 'remove static files etc.' and if they are checked then the files are removed?
*
*/
if( tdb->GetTicket(file_id, rm_ticket) == WINIX_ERR_OK )
{
tdb->RemoveTicket(file_id);
}
}
void TicketInfo::CopyTicketSpace(pt::Space & ticket_space, Item & item)
{
pt::Space & ticket_meta = item.item_content.meta.get_add_space(L"ticket");
ticket_meta = ticket_space;
}
void TicketInfo::MakeRedirectIfPossible(const Item & item)
{
PluginRes res = plugin->Call(WINIX_PL_TICKET_CAN_MAKE_REDIRECT);
if( res.res_false > 0 )
{
log << log4 << "Ticket: redirect prevented" << logend;
return;
}
system->RedirectTo(item);
}
} // namespace
} // namespace Winix