Rivendellaudio/lib/rdlog.cpp
Fred Gleason a851df85de 2022-12-13 Fred Gleason <fredg@paravelsystems.com>
* Fixed a bug in 'RDLog::create()' that threw a SQL error when
	attempting to create a log with a name that already existed.

Signed-off-by: Fred Gleason <fredg@paravelsystems.com>
2022-12-13 13:51:12 -05:00

784 lines
16 KiB
C++

// rdlog.cpp
//
// Abstract a Rivendell Log.
//
// (C) Copyright 2002-2022 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// 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.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "rdapplication.h"
#include "rddb.h"
#include "rdconf.h"
#include "rdescape_string.h"
#include "rdlog.h"
#include "rdlog_line.h"
#include "rdsvc.h"
#include "rdweb.h"
RDLog::RDLog(const QString &name)
{
log_name=name;
//
// Normalize case
//
QString sql=QString("select `NAME` from `LOGS` where ")+
"`NAME`='"+RDEscapeString(name)+"'";
RDSqlQuery *q=new RDSqlQuery(sql);
if(q->first()) {
log_name=q->value(0).toString();
}
delete q;
}
QString RDLog::name() const
{
return log_name;
}
bool RDLog::exists() const
{
QString sql=QString("select `NAME` from `LOGS` where ")+
"`NAME`='"+RDEscapeString(log_name)+"'";
RDSqlQuery *q=new RDSqlQuery(sql);
if(q->first()) {
delete q;
return true;
}
delete q;
return false;
}
bool RDLog::logExists() const
{
return RDBool(GetStringValue("LOG_EXISTS"));
}
void RDLog::setLogExists(bool state) const
{
SetRow("LOG_EXISTS",RDYesNo(state));
}
RDLog::Type RDLog::type() const
{
return(RDLog::Type)GetIntValue("TYPE");
}
void RDLog::setType(RDLog::Type type) const
{
SetRow("TYPE",(int)type);
}
QString RDLog::description() const
{
return GetStringValue("DESCRIPTION");
}
void RDLog::setDescription(const QString &desc) const
{
SetRow("DESCRIPTION",desc);
}
QString RDLog::service() const
{
return GetStringValue("SERVICE");
}
void RDLog::setService(const QString &svc) const
{
SetRow("SERVICE",svc);
}
QDate RDLog::startDate() const
{
return GetDateValue("START_DATE");
}
void RDLog::setStartDate(const QDate &date) const
{
SetRow("START_DATE",date);
}
QDate RDLog::endDate() const
{
return GetDateValue("END_DATE");
}
void RDLog::setEndDate(const QDate &date) const
{
SetRow("END_DATE",date);
}
QDate RDLog::purgeDate() const
{
return GetDateValue("PURGE_DATE");
}
void RDLog::setPurgeDate(const QDate &date) const
{
SetRow("PURGE_DATE",date);
}
QString RDLog::originUser() const
{
return GetStringValue("ORIGIN_USER");
}
void RDLog::setOriginUser(const QString &user) const
{
SetRow("ORIGIN_USER",user);
}
QDateTime RDLog::originDatetime() const
{
return GetDatetimeValue("ORIGIN_DATETIME");
}
void RDLog::setOriginDatetime(const QDateTime &datetime) const
{
SetRow("ORIGIN_DATETIME",datetime);
}
QDateTime RDLog::linkDatetime() const
{
return GetDatetimeValue("LINK_DATETIME");
}
void RDLog::setLinkDatetime(const QDateTime &datetime) const
{
SetRow("LINK_DATETIME",datetime);
}
QDateTime RDLog::modifiedDatetime() const
{
return GetDatetimeValue("MODIFIED_DATETIME");
}
void RDLog::setModifiedDatetime(const QDateTime &datetime) const
{
SetRow("MODIFIED_DATETIME",datetime);
}
bool RDLog::autoRefresh() const
{
return RDBool(GetStringValue("AUTO_REFRESH"));
}
void RDLog::setAutoRefresh(bool state) const
{
SetRow("AUTO_REFRESH",RDYesNo(state));
}
unsigned RDLog::scheduledTracks() const
{
return GetUnsignedValue("SCHEDULED_TRACKS");
}
void RDLog::setScheduledTracks(unsigned tracks) const
{
SetRow("SCHEDULED_TRACKS",tracks);
}
unsigned RDLog::completedTracks() const
{
return GetUnsignedValue("COMPLETED_TRACKS");
}
void RDLog::setCompletedTracks(unsigned tracks) const
{
SetRow("COMPLETED_TRACKS",tracks);
}
bool RDLog::includeImportMarkers(RDLog::Source src) const
{
if(src==RDLog::SourceMusic) {
return RDBool(GetStringValue("INCLUDE_MUS_IMPORT_MARKERS"));
}
return RDBool(GetStringValue("INCLUDE_TFC_IMPORT_MARKERS"));
}
void RDLog::setIncludeImportMarkers(RDLog::Source src,bool state)
{
if(src==RDLog::SourceMusic) {
SetRow("INCLUDE_MUS_IMPORT_MARKERS",RDYesNo(state));
}
else {
SetRow("INCLUDE_TFC_IMPORT_MARKERS",RDYesNo(state));
}
}
int RDLog::linkQuantity(RDLog::Source src) const
{
switch(src) {
case RDLog::SourceMusic:
return GetIntValue("MUSIC_LINKS");
case RDLog::SourceTraffic:
return GetIntValue("TRAFFIC_LINKS");
}
return 0;
}
void RDLog::setLinkQuantity(RDLog::Source src,int quan) const
{
switch(src) {
case RDLog::SourceMusic:
SetRow("MUSIC_LINKS",quan);
break;
case RDLog::SourceTraffic:
SetRow("TRAFFIC_LINKS",quan);
break;
}
}
void RDLog::updateLinkQuantity(RDLog::Source src) const
{
QString sql;
RDSqlQuery *q;
switch(src) {
case RDLog::SourceMusic:
sql=QString("select `LINE_ID` from `LOG_LINES` where ")+
"`LOG_NAME`='"+RDEscapeString(log_name)+"' && "+
QString::asprintf("`TYPE`=%d",RDLogLine::MusicLink);
q=new RDSqlQuery(sql);
sql=QString("update `LOGS` set ")+
QString::asprintf("`MUSIC_LINKS`=%d ",q->size())+
"where `NAME`='"+RDEscapeString(log_name)+"'";
break;
case RDLog::SourceTraffic:
sql=QString("select `LINE_ID` from `LOG_LINES` where ")+
"`LOG_NAME`='"+RDEscapeString(log_name)+"' && "+
QString::asprintf("`TYPE`=%d",RDLogLine::TrafficLink);
q=new RDSqlQuery(sql);
sql=QString("update `LOGS` set ")+
QString::asprintf("`TRAFFIC_LINKS`=%d ",q->size())+
"where `NAME`='"+RDEscapeString(log_name)+"'";
break;
default:
return;
}
delete q;
q=new RDSqlQuery(sql);
delete q;
}
RDLog::LinkState RDLog::linkState(RDLog::Source src) const
{
if(linkQuantity(src)==0) {
return RDLog::LinkNotPresent;
}
switch(src) {
case RDLog::SourceMusic:
return (RDLog::LinkState)RDBool(GetStringValue("MUSIC_LINKED"));
case RDLog::SourceTraffic:
return (RDLog::LinkState)RDBool(GetStringValue("TRAFFIC_LINKED"));
}
return RDLog::LinkNotPresent;
}
void RDLog::setLinkState(RDLog::Source src,bool state) const
{
switch(src) {
case RDLog::SourceMusic:
SetRow("MUSIC_LINKED",RDYesNo(state));
break;
case RDLog::SourceTraffic:
SetRow("TRAFFIC_LINKED",RDYesNo(state));
break;
}
}
int RDLog::nextId() const
{
return GetIntValue("NEXT_ID");
}
void RDLog::setNextId(int id) const
{
SetRow("NEXT_ID",id);
}
bool RDLog::isReady() const
{
QString sql;
RDSqlQuery *q;
bool ret=false;
sql=QString("select ")+
"`MUSIC_LINKS`,"+ // 00
"`MUSIC_LINKED`,"+ // 01
"`TRAFFIC_LINKS`,"+ // 02
"`TRAFFIC_LINKED`,"+ // 03
"`SCHEDULED_TRACKS`,"+ // 04
"`COMPLETED_TRACKS` "+ // 05
"from `LOGS` where "+
"`NAME`='"+RDEscapeString(log_name)+"'";
q=new RDSqlQuery(sql);
if(q->first()) {
ret=((q->value(0).toInt()==0)||(q->value(1).toString()=="Y"))&&
((q->value(2).toInt()==0)||(q->value(3).toString()=="Y"))&&
((q->value(4).toInt()==0)||(q->value(4).toInt()==q->value(5).toInt()));
}
delete q;
return ret;
}
bool RDLog::remove(RDStation *station,RDUser *user,RDConfig *config) const
{
QString sql;
RDSqlQuery *q;
if(removeTracks(station,user,config)<0) {
return false;
}
sql=QString("delete from `LOG_LINES` where ")+
"`LOG_NAME`='"+RDEscapeString(log_name)+"'";
RDSqlQuery::apply(sql);
sql=QString("delete from `LOGS` where ")+
"`NAME`='"+RDEscapeString(log_name)+"' && "+
"`TYPE`=0";
q=new RDSqlQuery(sql);
delete q;
return true;
}
void RDLog::updateTracks()
{
QString sql;
RDSqlQuery *q;
unsigned scheduled=0;
unsigned completed=0;
sql=QString("select `LOG_LINES`.`LINE_ID` from ")+
"`LOG_LINES` left join `CART` "+
"on `LOG_LINES`.`CART_NUMBER`=`CART`.`NUMBER` where "+
"`LOG_NAME`='"+RDEscapeString(log_name)+"' && "+
"`CART`.`OWNER` is not null";
q=new RDSqlQuery(sql);
completed=q->size();
delete q;
sql=QString("select `LINE_ID` from `LOG_LINES` where ")+
"`LOG_NAME`='"+RDEscapeString(log_name)+"' && "+
QString::asprintf("`TYPE`=%d",RDLogLine::Track);
q=new RDSqlQuery(sql);
scheduled=q->size()+completed;
delete q;
sql=QString("update `LOGS` set ")+
QString::asprintf("`SCHEDULED_TRACKS`=%d,",scheduled)+
QString::asprintf("`COMPLETED_TRACKS`=%u where ",completed)+
"NAME=\""+RDEscapeString(log_name)+"\"";
q=new RDSqlQuery(sql);
delete q;
}
int RDLog::removeTracks(RDStation *station,RDUser *user,RDConfig *config) const
{
QString sql;
RDSqlQuery *q;
int count=0;
RDCart *cart;
QString owner=log_name;
owner.replace(" ","_");
sql=QString("select `NUMBER` from `CART` where ")+
"`OWNER`='"+RDEscapeString(owner)+"'";
q=new RDSqlQuery(sql);
while(q->next()) {
cart=new RDCart(q->value(0).toUInt());
if(!cart->remove(station,user,config)) {
delete cart;
return -1;
}
delete cart;
count++;
}
delete q;
return count;
}
RDLogModel *RDLog::createLogEvent() const
{
return new RDLogModel(name(),false);
}
QString RDLog::xml() const
{
QString sql;
RDSqlQuery *q;
QString ret;
sql=QString("select ")+
"`NAME`,"+ // 00
"`SERVICE`,"+ // 01
"`DESCRIPTION`,"+ // 02
"`ORIGIN_USER`,"+ // 03
"`ORIGIN_DATETIME`,"+ // 04
"`LINK_DATETIME`,"+ // 05
"`MODIFIED_DATETIME`,"+ // 06
"`PURGE_DATE`,"+ // 07
"`AUTO_REFRESH`,"+ // 08
"`START_DATE`,"+ // 09
"`END_DATE`,"+ // 10
"`SCHEDULED_TRACKS`,"+ // 11
"`COMPLETED_TRACKS`,"+ // 12
"`MUSIC_LINKS`,"+ // 13
"`MUSIC_LINKED`,"+ // 14
"`TRAFFIC_LINKS`,"+ // 15
"`TRAFFIC_LINKED`,"+ // 16
"`NEXT_ID` "+ // 17
"from `LOGS` where `NAME`='"+RDEscapeString(log_name)+"'";
q=new RDSqlQuery(sql);
if(q->first()) {
ret+=" <log>\n";
ret+=" "+RDXmlField("name",log_name);
ret+=" "+RDXmlField("serviceName",q->value(1).toString());
ret+=" "+RDXmlField("description",q->value(2).toString());
ret+=" "+RDXmlField("originUserName",q->value(3).toString());
ret+=" "+RDXmlField("originDatetime",q->value(4).toDateTime());
ret+=" "+RDXmlField("linkDatetime",q->value(5).toDateTime());
ret+=" "+RDXmlField("modifiedDatetime",q->value(6).toDateTime());
ret+=" "+RDXmlField("purgeDate",q->value(7).toDate());
ret+=" "+RDXmlField("autoRefresh",RDBool(q->value(8).toString()));
ret+=" "+RDXmlField("startDate",q->value(9).toDate());
ret+=" "+RDXmlField("endDate",q->value(10).toDate());
ret+=" "+RDXmlField("scheduledTracks",q->value(11).toInt());
ret+=" "+RDXmlField("completedTracks",q->value(12).toInt());
ret+=" "+RDXmlField("musicLinks",q->value(13).toInt());
ret+=" "+RDXmlField("musicLinked",RDBool(q->value(14).toString()));
ret+=" "+RDXmlField("trafficLinks",q->value(15).toInt());
ret+=" "+RDXmlField("trafficLinked",RDBool(q->value(16).toString()));
ret+=" </log>\n";
}
delete q;
return ret;
}
bool RDLog::create(const QString &name,const QString &svc_name,
const QDate &air_date,const QString &user_name,
QString *err_msg,RDConfig *config)
{
QString sql;
RDSqlQuery *q;
int shelflife=-1;
RDSvc::ShelflifeOrigin shelforigin;
QString desc_tmpl;
if(RDLog::exists(name)) {
*err_msg=QObject::tr("Log already exists!");
return false;
}
sql=QString("select ")+
"`DEFAULT_LOG_SHELFLIFE`,"+ // 00
"`LOG_SHELFLIFE_ORIGIN`,"+ // 01
"`DESCRIPTION_TEMPLATE` "+ // 02
"from `SERVICES` where "+
"`NAME`='"+RDEscapeString(svc_name)+"'";
q=new RDSqlQuery(sql);
if(q->first()) {
shelflife=q->value(0).toInt();
shelforigin=(RDSvc::ShelflifeOrigin)q->value(1).toInt();
desc_tmpl=q->value(2).toString();
}
else {
*err_msg=QObject::tr("No such service!");
delete q;
return false;
}
delete q;
sql=QString("insert into `LOGS` set ")+
"`NAME`=\""+RDEscapeString(name)+"\","+
"`TYPE`=0,"+
"`DESCRIPTION`='"+RDEscapeString(name)+" log ',"+
"`ORIGIN_USER`='"+RDEscapeString(user_name)+"',"+
"`ORIGIN_DATETIME`=now(),"+
"`MODIFIED_DATETIME`=now(),"+
"`LINK_DATETIME`=now(),"+
"`SERVICE`='"+RDEscapeString(svc_name)+"'";
if(shelflife>=0) {
switch(shelforigin) {
case RDSvc::OriginCreationDate:
sql+=",`PURGE_DATE`='"+
QDate::currentDate().addDays(shelflife).toString("yyyy-MM-dd")+"'";
break;
case RDSvc::OriginAirDate:
if(air_date.isValid()) {
sql+=",`PURGE_DATE`='"+
air_date.addDays(shelflife).toString("yyyy-MM-dd")+"'";
}
break;
}
}
q=new RDSqlQuery(sql);
if(!q->isActive()) {
*err_msg=QObject::tr("Insertion into LOGS table failed!");
delete q;
return false;
}
delete q;
*err_msg=QObject::tr("OK");
return true;
}
bool RDLog::exists(const QString &name)
{
QString sql;
RDSqlQuery *q;
bool ret=false;
sql=QString("select `NAME` from `LOGS` where `NAME`='")+
RDEscapeString(name)+"'";
q=new RDSqlQuery(sql);
ret=q->first();
delete q;
return ret;
}
bool RDLog::remove(const QString &name,RDStation *station,RDUser *user,
RDConfig *config)
{
RDLog *log=new RDLog(name);
bool ret=false;
ret=log->remove(station,user,config);
delete log;
return ret;
}
int RDLog::GetIntValue(const QString &field) const
{
QString sql;
RDSqlQuery *q;
int accum;
sql=QString("select `")+field+"` from `LOGS` where "+
"`NAME`='"+RDEscapeString(log_name)+"'";
q=new RDSqlQuery(sql);
if(q->first()) {
accum=q->value(0).toInt();
delete q;
return accum;
}
delete q;
return 0;
}
unsigned RDLog::GetUnsignedValue(const QString &field) const
{
QString sql;
RDSqlQuery *q;
unsigned accum;
sql=QString("select `")+
field+"` from `LOGS` where "+
"`NAME`='"+RDEscapeString(log_name)+"'";
q=new RDSqlQuery(sql);
if(q->first()) {
accum=q->value(0).toUInt();
delete q;
return accum;
}
delete q;
return 0;
}
QString RDLog::GetStringValue(const QString &field) const
{
QString sql;
RDSqlQuery *q;
QString accum;
sql=QString("select `")+
field+"` from `LOGS` where "+
"`NAME`='"+RDEscapeString(log_name)+"'";
q=new RDSqlQuery(sql);
if(q->first()) {
accum=q->value(0).toString();
}
delete q;
return accum;
}
QDate RDLog::GetDateValue(const QString &field) const
{
QString sql;
RDSqlQuery *q;
QDate accum;
sql=QString("select `")+
field+"` from `LOGS` where "+
"`NAME`='"+RDEscapeString(log_name)+"'";
q=new RDSqlQuery(sql);
if(q->first()) {
accum=q->value(0).toDate();
delete q;
return accum;
}
delete q;
return QDate();
}
QDateTime RDLog::GetDatetimeValue(const QString &field) const
{
QString sql;
RDSqlQuery *q;
QDateTime accum;
sql=QString("select `")+
field+"` from `LOGS` where "+
"`NAME`='"+RDEscapeString(log_name)+"'";
q=new RDSqlQuery(sql);
if(q->first()) {
accum=q->value(0).toDateTime();
delete q;
return accum;
}
delete q;
return QDateTime();
}
void RDLog::SetRow(const QString &param,int value) const
{
RDSqlQuery *q;
QString sql;
sql=QString("update LOGS set `")+
param+QString::asprintf("`=%d where ",value)+
"`NAME`='"+RDEscapeString(log_name)+"'";
q=new RDSqlQuery(sql);
delete q;
}
void RDLog::SetRow(const QString &param,unsigned value) const
{
RDSqlQuery *q;
QString sql;
sql=QString("update LOGS set `")+
param+QString::asprintf("`=%u where ",value)+
"`NAME`='"+RDEscapeString(log_name)+"'";
q=new RDSqlQuery(sql);
delete q;
}
void RDLog::SetRow(const QString &param,const QString &value) const
{
RDSqlQuery *q;
QString sql;
sql=QString("update LOGS set `")+
param+"`='"+RDEscapeString(value)+"' where "+
"`NAME`='"+RDEscapeString(log_name)+"'";
q=new RDSqlQuery(sql);
delete q;
}
void RDLog::SetRow(const QString &param,const QDate &value) const
{
RDSqlQuery *q;
QString sql;
sql=QString("update LOGS set `")+
param+"`="+RDCheckDateTime(value,"yyyy/MM/dd")+" where "+
"`NAME`='"+RDEscapeString(log_name)+"'";
q=new RDSqlQuery(sql);
delete q;
}
void RDLog::SetRow(const QString &param,const QDateTime &value) const
{
RDSqlQuery *q;
QString sql;
sql=QString("update LOGS set `")+
param+"`="+RDCheckDateTime(value,"yyyy-MM-dd hh:mm:ss")+" where "+
"`NAME`='"+RDEscapeString(log_name)+"'";
q=new RDSqlQuery(sql);
delete q;
}