2020-09-21 Fred Gleason <fredg@paravelsystems.com>

* Added a 'PostPodcast' method to the Web API.
	* Added a 'RemovePodcast' method to the Web API.
	* Added a 'PostRss' method to the Web API.
	* Added a 'RemoveRss' method to the Web API.

Signed-off-by: Fred Gleason <fredg@paravelsystems.com>
This commit is contained in:
Fred Gleason
2020-09-22 15:20:01 -04:00
parent 5349a8e853
commit 5a549b7866
34 changed files with 1163 additions and 281 deletions

View File

@@ -24,18 +24,40 @@
#include <fcntl.h>
#include <errno.h>
#include <curl/curl.h>
#include <rdapplication.h>
#include <rdconf.h>
#include <rddelete.h>
#include <rdescape_string.h>
#include <rdfeed.h>
#include <rdformpost.h>
#include <rdgroup.h>
#include <rdhash.h>
#include <rdpodcast.h>
#include <rdupload.h>
#include <rduser.h>
#include <rdweb.h>
#include "rdxport.h"
size_t __PostRss_Readfunction_Callback(char *buffer,size_t size,size_t nitems,
void *userdata)
{
Xport *xport=(Xport *)userdata;
int curlsize=size*nitems;
int segsize=xport->xport_curl_data.size()-xport->xport_curl_data_ptr;
if(segsize<curlsize) {
curlsize=segsize;
}
memcpy(buffer,xport->xport_curl_data.mid(xport->xport_curl_data_ptr,curlsize).constData(),
curlsize);
xport->xport_curl_data_ptr+=curlsize;
return curlsize;
}
void Xport::SavePodcast()
{
int cast_id=0;
@@ -64,7 +86,9 @@ void Xport::SavePodcast()
XmlExit("No such podcast",404,"podcasts.cpp",LINE_NUMBER);
}
keyname=cast->keyName();
if((!rda->user()->addPodcast())||(!rda->user()->feedAuthorized(keyname))) {
if(((!rda->user()->addPodcast())||
(!rda->user()->feedAuthorized(keyname)))&&
(!rda->user()->adminConfig())) {
delete cast;
XmlExit("No such podcast",404,"podcasts.cpp",LINE_NUMBER);
}
@@ -122,7 +146,9 @@ void Xport::GetPodcast()
XmlExit("No such podcast",404,"podcasts.cpp",LINE_NUMBER);
}
keyname=cast->keyName();
if((!rda->user()->editPodcast())||(!rda->user()->feedAuthorized(keyname))) {
if(((!rda->user()->addPodcast())||
(!rda->user()->feedAuthorized(keyname)))&&
(!rda->user()->adminConfig())) {
delete cast;
XmlExit("No such podcast",404,"podcasts.cpp",LINE_NUMBER);
}
@@ -180,7 +206,9 @@ void Xport::DeletePodcast()
XmlExit("No such podcast",404,"podcasts.cpp",LINE_NUMBER);
}
keyname=cast->keyName();
if((!rda->user()->deletePodcast())||(!rda->user()->feedAuthorized(keyname))) {
if(((!rda->user()->deletePodcast())||
(!rda->user()->feedAuthorized(keyname)))&&
(!rda->user()->adminConfig())) {
delete cast;
XmlExit("No such podcast",404,"podcasts.cpp",LINE_NUMBER);
}
@@ -205,3 +233,289 @@ void Xport::DeletePodcast()
Exit(0);
}
void Xport::PostPodcast()
{
int cast_id=0;
QString keyname;
QString destpath;
QString err_msg;
RDPodcast *cast=NULL;
RDFeed *feed=NULL;
QString msg="OK";
RDUpload::ErrorCode upload_err;
if(!xport_post->getValue("ID",&cast_id)) {
XmlExit("Missing ID",400,"podcasts.cpp",LINE_NUMBER);
}
cast=new RDPodcast(rda->config(),cast_id);
if(!cast->exists()) {
delete cast;
XmlExit("No such podcast",404,"podcasts.cpp",LINE_NUMBER);
}
keyname=cast->keyName();
if(((!rda->user()->addPodcast())||
(!rda->user()->feedAuthorized(keyname)))&&
(!rda->user()->adminConfig())) {
delete cast;
XmlExit("No such podcast",404,"podcasts.cpp",LINE_NUMBER);
}
destpath=QString(RD_AUDIO_ROOT)+"/"+cast->audioFilename();
feed=new RDFeed(keyname,rda->config(),this);
RDUpload *upload=new RDUpload(rda->config(),this);
upload->setSourceFile(destpath);
QString desturl=feed->purgeUrl()+"/"+cast->audioFilename();
upload->setDestinationUrl(desturl);
if((upload_err=upload->
runUpload(feed->purgeUsername(),feed->purgePassword(),
rda->station()->sshIdentityFile(),feed->purgeUseIdFile(),
rda->config()->logXloadDebugData()))!=RDUpload::ErrorOk) {
delete upload;
delete feed;
delete cast;
XmlExit(QString("Upload to \"")+desturl+"\" failed ["+
RDUpload::errorText(upload_err)+"]",500,"podcasts.cpp",LINE_NUMBER);
}
delete upload;
printf("Content-type: text/html; charset: UTF-8\n");
printf("Status: 200\n\n");
printf("OK\n");
rda->syslog(LOG_DEBUG,
"posted podcast audio \"%s\"",destpath.toUtf8().constData());
delete feed;
delete cast;
Exit(0);
}
void Xport::RemovePodcast()
{
int cast_id=0;
QString keyname;
QString destpath;
QString err_msg;
RDPodcast *cast=NULL;
RDFeed *feed=NULL;
QString msg="OK";
RDDelete::ErrorCode del_err;
if(!xport_post->getValue("ID",&cast_id)) {
XmlExit("Missing ID",400,"podcasts.cpp",LINE_NUMBER);
}
cast=new RDPodcast(rda->config(),cast_id);
if(!cast->exists()) {
delete cast;
XmlExit("No such podcast",404,"podcasts.cpp",LINE_NUMBER);
}
keyname=cast->keyName();
if(((!rda->user()->deletePodcast())||
(!rda->user()->feedAuthorized(keyname)))&&
(!rda->user()->adminConfig())) {
delete cast;
XmlExit("No such podcast",404,"podcasts.cpp",LINE_NUMBER);
}
destpath=QString(RD_AUDIO_ROOT)+"/"+cast->audioFilename();
feed=new RDFeed(keyname,rda->config(),this);
RDDelete *del=new RDDelete(rda->config(),this);
QString desturl=feed->purgeUrl()+"/"+cast->audioFilename();
del->setTargetUrl(desturl);
if((del_err=del->
runDelete(feed->purgeUsername(),feed->purgePassword(),
rda->station()->sshIdentityFile(),feed->purgeUseIdFile(),
rda->config()->logXloadDebugData()))!=RDDelete::ErrorOk) {
delete del;
delete feed;
delete cast;
XmlExit(QString("Deletion of \"")+desturl+"\" failed ["+
RDDelete::errorText(del_err)+"]",500,"podcasts.cpp",LINE_NUMBER);
}
delete del;
printf("Content-type: text/html; charset: UTF-8\n");
printf("Status: 200\n\n");
printf("OK\n");
rda->syslog(LOG_DEBUG,
"delete podcast audio \"%s\"",destpath.toUtf8().constData());
delete feed;
delete cast;
Exit(0);
}
void Xport::PostRss()
{
int feed_id=0;
QString keyname;
QString destpath;
QString err_msg;
RDFeed *feed=NULL;
QString msg="OK";
bool ret=false;
CURL *curl=NULL;
CURLcode curl_err;
char errstr[CURL_ERROR_SIZE];
QDateTime now=QDateTime::currentDateTime();
if(!xport_post->getValue("ID",&feed_id)) {
XmlExit("Missing ID",400,"podcasts.cpp",LINE_NUMBER);
}
feed=new RDFeed(feed_id,rda->config(),this);
if(!feed->exists()) {
XmlExit("No such feed",404,"podcasts.cpp",LINE_NUMBER);
}
keyname=feed->keyName();
if(((!rda->user()->editPodcast())||
(!rda->user()->feedAuthorized(keyname)))&&
(!rda->user()->adminConfig())) {
delete feed;
XmlExit("No such feed",404,"podcasts.cpp",LINE_NUMBER);
}
if((curl=curl_easy_init())==NULL) {
XmlExit("unable to get CURL handle",500,"podcasts.cpp",LINE_NUMBER);
}
xport_curl_data=feed->rssXml(&err_msg,now).toUtf8();
xport_curl_data_ptr=0;
//
// Authentication
//
if((QUrl(feed->feedUrl()).scheme().toLower()=="sftp")&&
(!rda->station()->sshIdentityFile().isEmpty())&&feed->purgeUseIdFile()) {
curl_easy_setopt(curl,CURLOPT_USERNAME,
feed->purgeUsername().toUtf8().constData());
curl_easy_setopt(curl,CURLOPT_SSH_PRIVATE_KEYFILE,
rda->station()->sshIdentityFile().toUtf8().constData());
curl_easy_setopt(curl,CURLOPT_KEYPASSWD,
feed->purgePassword().toUtf8().constData());
}
else {
curl_easy_setopt(curl,CURLOPT_USERNAME,
feed->purgeUsername().toUtf8().constData());
curl_easy_setopt(curl,CURLOPT_PASSWORD,
feed->purgePassword().toUtf8().constData());
}
curl_easy_setopt(curl,CURLOPT_URL,feed->feedUrl().toUtf8().constData());
curl_easy_setopt(curl,CURLOPT_UPLOAD,1);
curl_easy_setopt(curl,CURLOPT_READFUNCTION, __PostRss_Readfunction_Callback);
curl_easy_setopt(curl,CURLOPT_READDATA,this);
curl_easy_setopt(curl,CURLOPT_TIMEOUT,RD_CURL_TIMEOUT);
curl_easy_setopt(curl,CURLOPT_NOPROGRESS,1);
curl_easy_setopt(curl,CURLOPT_USERAGENT,
(const char *)rda->config()->userAgent().utf8());
curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,errstr);
//curl_easy_setopt(curl,CURLOPT_VERBOSE,1);
//curl_easy_setopt(curl,CURLOPT_DEBUGFUNCTION,UploadErrorCallback);
switch((curl_err=curl_easy_perform(curl))) {
case CURLE_OK:
case CURLE_PARTIAL_FILE:
feed->setLastBuildDateTime(now);
ret=true;
break;
default:
err_msg=errstr;
ret=false;
break;
}
curl_easy_cleanup(curl);
//
// Update Enclosing Superfeeds
//
QStringList superfeeds=feed->isSubfeedOf();
for(int i=0;i<superfeeds.size();i++) {
QString err_msg2;
RDFeed *feed=new RDFeed(superfeeds.at(i),rda->config(),this);
if(!feed->postXml(&err_msg2)) {
err_msg+="\n"+err_msg2;
}
delete feed;
}
if(!ret) {
XmlExit(err_msg,500,"podcasts.cpp",LINE_NUMBER);
}
printf("Content-type: text/html; charset: UTF-8\n");
printf("Status: 200\n\n");
printf("OK\n");
rda->syslog(LOG_DEBUG,
"posted RSS XML to \"%s\"",feed->feedUrl().toUtf8().constData());
Exit(0);
}
void Xport::RemoveRss()
{
int feed_id=0;
RDFeed *feed=NULL;
QString keyname;
QString destpath;
QString err_msg;
// RDPodcast *cast=NULL;
QString msg="OK";
RDDelete::ErrorCode del_err;
if(!xport_post->getValue("ID",&feed_id)) {
XmlExit("Missing ID",400,"podcasts.cpp",LINE_NUMBER);
}
feed=new RDFeed(feed_id,rda->config(),this);
if(!feed->exists()) {
XmlExit("No such feed",404,"podcasts.cpp",LINE_NUMBER);
}
keyname=feed->keyName();
if(((!rda->user()->deletePodcast())||
(!rda->user()->feedAuthorized(keyname)))&&
(!rda->user()->adminConfig())) {
delete feed;
XmlExit("No such feed",404,"podcasts.cpp",LINE_NUMBER);
}
RDDelete *del=new RDDelete(rda->config(),this);
QString desturl=feed->feedUrl();
del->setTargetUrl(desturl);
if((del_err=del->
runDelete(feed->purgeUsername(),feed->purgePassword(),
rda->station()->sshIdentityFile(),feed->purgeUseIdFile(),
rda->config()->logXloadDebugData()))!=RDDelete::ErrorOk) {
delete del;
delete feed;
XmlExit(QString("Deletion of \"")+desturl+"\" failed ["+
RDDelete::errorText(del_err)+"]",500,"podcasts.cpp",LINE_NUMBER);
}
delete del;
printf("Content-type: text/html; charset: UTF-8\n");
printf("Status: 200\n\n");
printf("OK\n");
rda->syslog(LOG_DEBUG,
"deleted podcast RSS \"%s\"",destpath.toUtf8().constData());
delete feed;
Exit(0);
}