Commit 162c6473 authored by Malcolm Blaney's avatar Malcolm Blaney

Refactored Reader module and SimplePie Parser to handle microformats

more cleanly. Some properties are now stored using Media RSS extension
so that they can be accessed as enclosures using SimplePie API. Also
moved custom lightbox code to Reader module. Image handler needs to be
the full url for Microsub clients. Other changes are mostly formatting
and a few small bug fixes.
parent 45d7d97f
Pipeline #34760507 passed with stage
in 1 minute and 24 seconds
...@@ -41,13 +41,13 @@ class Analytics extends Base { ...@@ -41,13 +41,13 @@ class Analytics extends Base {
$mysqli = connect_db(); $mysqli = connect_db();
$referer = isset($_SERVER['HTTP_REFERER']) ? $referer = isset($_SERVER['HTTP_REFERER']) ?
$mysqli->escape_string($_SERVER['HTTP_REFERER']) : ''; $mysqli->escape_string($_SERVER['HTTP_REFERER']) : '';
// The current time is converted to a timestamp on the hour. // The current time is quantized to a timestamp on the hour.
$timestamp = strtotime(date('F j Y H:00:00').' UTC'); $timestamp = strtotime(date('F j Y H:00:00') . ' UTC');
$query = 'INSERT INTO analytics VALUES ("'.$this->owner.'", '. $query = 'INSERT INTO analytics VALUES ("' . $this->owner . '", ' .
'"'.$this->user->page.'", '.$timestamp.', "'.$referer.'", 1) '. '"' . $this->user->page . '", ' . $timestamp . ', "' . $referer . '", ' .
'ON DUPLICATE KEY UPDATE counter = counter + 1'; '1) ON DUPLICATE KEY UPDATE counter = counter + 1';
if (!$mysqli->query($query)) { if (!$mysqli->query($query)) {
$this->Log('Analytics->Content: '.$mysqli->error); $this->Log('Analytics->Content: ' . $mysqli->error);
} }
$mysqli->close(); $mysqli->close();
return false; return false;
...@@ -143,10 +143,10 @@ class Analytics extends Base { ...@@ -143,10 +143,10 @@ class Analytics extends Base {
public function Referers($start, $end) { public function Referers($start, $end) {
$data = []; $data = [];
$mysqli = connect_db(); $mysqli = connect_db();
$query = 'SELECT user, page, referer, SUM(counter) AS counter FROM '. $query = 'SELECT user, page, referer, SUM(counter) AS counter FROM ' .
'analytics WHERE referer != "" AND timestamp >= '.$start.' AND '. 'analytics WHERE referer != "" AND timestamp >= ' . $start . ' AND ' .
'timestamp <= '.$end.' GROUP BY user, page, referer ORDER BY counter '. 'timestamp <= ' . $end . ' GROUP BY user, page, referer ORDER BY ' .
'DESC'; 'counter DESC';
if ($result = $mysqli->query($query)) { if ($result = $mysqli->query($query)) {
while ($analytics = $result->fetch_assoc()) { while ($analytics = $result->fetch_assoc()) {
$data[] = ['user' => $analytics['user'], $data[] = ['user' => $analytics['user'],
...@@ -157,7 +157,7 @@ class Analytics extends Base { ...@@ -157,7 +157,7 @@ class Analytics extends Base {
$result->close(); $result->close();
} }
else { else {
$this->Log('Analytics->Referers: '.$mysqli->error); $this->Log('Analytics->Referers: ' . $mysqli->error);
} }
$mysqli->close(); $mysqli->close();
return $data; return $data;
...@@ -166,8 +166,8 @@ class Analytics extends Base { ...@@ -166,8 +166,8 @@ class Analytics extends Base {
public function Total($start, $end) { public function Total($start, $end) {
$total = 0; $total = 0;
$mysqli = connect_db(); $mysqli = connect_db();
$query = 'SELECT SUM(counter) AS counter FROM analytics WHERE '. $query = 'SELECT SUM(counter) AS counter FROM analytics WHERE ' .
'timestamp >= '.$start.' AND timestamp <= '.$end; 'timestamp >= ' . $start . ' AND timestamp <= ' . $end;
if ($result = $mysqli->query($query)) { if ($result = $mysqli->query($query)) {
if ($analytics = $result->fetch_assoc()) { if ($analytics = $result->fetch_assoc()) {
$total = (int)$analytics['counter']; $total = (int)$analytics['counter'];
...@@ -175,7 +175,7 @@ class Analytics extends Base { ...@@ -175,7 +175,7 @@ class Analytics extends Base {
$result->close(); $result->close();
} }
else { else {
$this->Log('Analytics->Total: '.$mysqli->error); $this->Log('Analytics->Total: ' . $mysqli->error);
} }
$mysqli->close(); $mysqli->close();
return $total; return $total;
......
...@@ -83,6 +83,7 @@ class Grid extends Base { ...@@ -83,6 +83,7 @@ class Grid extends Base {
'"",".slick-cell > input[type=text]","border","none"', '"",".slick-cell > input[type=text]","border","none"',
'"",".slick-cell > input[type=text]","width","100%"', '"",".slick-cell > input[type=text]","width","100%"',
'"",".slick-cell > input[type=text]","height","100%"', '"",".slick-cell > input[type=text]","height","100%"',
'"",".slick-cell > a","text-decoration","none"',
'"","button.long-text-save","float","right"']; '"","button.long-text-save","float","right"'];
$this->AddSiteStyle($site_style); $this->AddSiteStyle($site_style);
} }
......
This diff is collapsed.
<?php <?php
// Dobrado Content Management System // Dobrado Content Management System
// Copyright (C) 2017 Malcolm Blaney // Copyright (C) 2018 Malcolm Blaney
// //
// This program is free software: you can redistribute it and/or modify // This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as // it under the terms of the GNU Affero General Public License as
...@@ -30,8 +30,8 @@ class Viewanalytics extends Base { ...@@ -30,8 +30,8 @@ class Viewanalytics extends Base {
// end dates in local time to UTC. Want to display the data with local // end dates in local time to UTC. Want to display the data with local
// timestamps however, so also calculate the offset to local time. // timestamps however, so also calculate the offset to local time.
$offset = strtotime('UTC') - strtotime('now'); $offset = strtotime('UTC') - strtotime('now');
$start = strtotime(date('F j Y 00:00:00', $start).' UTC'); $start = strtotime(date('F j Y 00:00:00', $start) . ' UTC');
$end = strtotime(date('F j Y 23:59:59', $end).' UTC'); $end = strtotime(date('F j Y 23:59:59', $end) . ' UTC');
if (!$start || !$end || $start > $end) { if (!$start || !$end || $start > $end) {
return ['error' => 'Start and End dates required.']; return ['error' => 'Start and End dates required.'];
} }
...@@ -70,18 +70,18 @@ class Viewanalytics extends Base { ...@@ -70,18 +70,18 @@ class Viewanalytics extends Base {
} }
public function Content($id) { public function Content($id) {
return '<div class="viewanalytics-total-search">'. return '<form id="viewanalytics-total-search">' .
'Enter dates to view total visits:'. 'Enter dates to view total visits:' .
'<div class="form-spacing">'. '<div class="form-spacing">' .
'<label for="viewanalytics-total-start">Start:</label>'. '<label for="viewanalytics-total-start">Start:</label>' .
'<input id="viewanalytics-total-start" maxlength="50">'. '<input id="viewanalytics-total-start" maxlength="50">' .
'</div>'. '</div>' .
'<div class="form-spacing">'. '<div class="form-spacing">' .
'<label for="viewanalytics-total-end">End:</label>'. '<label for="viewanalytics-total-end">End:</label>' .
'<input id="viewanalytics-total-end" maxlength="50">'. '<input id="viewanalytics-total-end" maxlength="50">' .
'</div>'. '</div>' .
'<button id="viewanalytics-total-button">submit</button>'. '<button id="viewanalytics-total-button">submit</button>' .
'</div>'. '</form>' .
'<div class="viewanalytics-total-graph"></div>'; '<div class="viewanalytics-total-graph"></div>';
} }
...@@ -109,6 +109,9 @@ class Viewanalytics extends Base { ...@@ -109,6 +109,9 @@ class Viewanalytics extends Base {
// Need to call AppendScript here if module uses javascript. // Need to call AppendScript here if module uses javascript.
// Note that the module is only available when logged in. // Note that the module is only available when logged in.
$this->AppendScript($path, 'dobrado.viewanalytics.js', false); $this->AppendScript($path, 'dobrado.viewanalytics.js', false);
$site_style = ['"",".viewanalytics","font-family","Verdana,Arial"',
'"","#viewanalytics-total-search label","width","4em"',
'"","#viewanalytics-total-button","margin-left","3.9em"'];
} }
public function Placement() { public function Placement() {
......
...@@ -27,9 +27,10 @@ ...@@ -27,9 +27,10 @@
if(!this.dobrado.viewanalytics){dobrado.viewanalytics={};} if(!this.dobrado.viewanalytics){dobrado.viewanalytics={};}
(function(){'use strict';var analytics={};var totalGraphId='';var refererGrid=null;var refererGridId='';$(function(){if($('.viewanalytics').length===0){return;} (function(){'use strict';var analytics={};var totalGraphId='';var refererGrid=null;var refererGridId='';$(function(){if($('.viewanalytics').length===0){return;}
$('#viewanalytics-total-start').datepicker({dateFormat:dobrado.dateFormat}).val('');$('#viewanalytics-total-end').datepicker({dateFormat:dobrado.dateFormat}).val('');$('#viewanalytics-total-button').button().click(view);if($('.graph').length===1){var graphId='#'+$('.graph').attr('id');$(graphId+' .graph-area').each(function(index){if(index===0){totalGraphId=$(this).attr('id');$('#'+totalGraphId).parent().hide();}});} $('#viewanalytics-total-start').datepicker({dateFormat:dobrado.dateFormat}).val('');$('#viewanalytics-total-end').datepicker({dateFormat:dobrado.dateFormat}).val('');$('#viewanalytics-total-button').button().click(view);if($('.graph').length===1){var graphId='#'+$('.graph').attr('id');$(graphId+' .graph-area').each(function(index){if(index===0){totalGraphId=$(this).attr('id');$('#'+totalGraphId).parent().hide();}});}
if($('.grid').length===1){refererGridId='#'+$('.grid').attr('id');var columns=[{id:"user",name:"User",field:"user",width:100,sortable:true},{id:"page",name:"Page",field:"page",width:150,sortable:true},{id:"referer",name:"Referer",field:"referer",width:400,sortable:true},{id:"counter",name:"#",field:"counter",width:50,sortable:true}];var options={autoHeight:true,forceFitColumns:true};refererGrid=dobrado.grid.instance(refererGridId,[],columns,options);refererGrid.onSort.subscribe(function(e,args){analytics.referers.sort(function(row1,row2){var field=args.sortCol.field;var sign=args.sortAsc?1:-1;var value1=row1[field];var value2=row2[field];if(value1===value2){return 0;} if($('.grid').length===1){refererGridId='#'+$('.grid').attr('id');var columns=[{id:"user",name:"User",field:"user",width:100,sortable:true},{id:"page",name:"Page",field:"page",width:150,sortable:true},{id:"referer",name:"Referer",field:"referer",width:400,sortable:true,formatter:refererFormatter},{id:"counter",name:"#",field:"counter",width:50,sortable:true}];var options={autoHeight:true,forceFitColumns:true};refererGrid=dobrado.grid.instance(refererGridId,[],columns,options);refererGrid.onSort.subscribe(function(e,args){analytics.referers.sort(function(row1,row2){var field=args.sortCol.field;var sign=args.sortAsc?1:-1;var value1=row1[field];var value2=row2[field];if(value1===value2){return 0;}
if(value1>value2){return sign;} if(value1>value2){return sign;}
else{return sign* -1;}});refererGrid.invalidate();});} else{return sign* -1;}});refererGrid.invalidate();});}
setTimeout(view,500);});function view(){var start=parseInt($.datepicker.formatDate('@',$('#viewanalytics-total-start').datepicker('getDate')),10);var end=parseInt($.datepicker.formatDate('@',$('#viewanalytics-total-end').datepicker('getDate')),10);dobrado.log('Loading data.','info');$.post('/php/request.php',{request:'viewanalytics',start:start,end:end,url:location.href,token:dobrado.token},function(response){if(dobrado.checkResponseError(response,'viewanalytics')){return;} setTimeout(view,500);});function refererFormatter(row,cell,value,columnDef,dataContext){if(value==='')return'';return'<a href="'+value+'">'+value+'</a>';}
function view(){var start=parseInt($.datepicker.formatDate('@',$('#viewanalytics-total-start').datepicker('getDate')),10);var end=parseInt($.datepicker.formatDate('@',$('#viewanalytics-total-end').datepicker('getDate')),10);dobrado.log('Loading data.','info');$.post('/php/request.php',{request:'viewanalytics',start:start,end:end,url:location.href,token:dobrado.token},function(response){if(dobrado.checkResponseError(response,'viewanalytics')){return;}
analytics=JSON.parse(response);if(totalGraphId){$('#'+totalGraphId).html('').parent().hide();$('#'+totalGraphId).parent().appendTo('.viewanalytics-total-graph');if(analytics.data){$('#'+totalGraphId).parent().show();dobrado.graph.loadData(totalGraphId,analytics.data,analytics.series);}} analytics=JSON.parse(response);if(totalGraphId){$('#'+totalGraphId).html('').parent().hide();$('#'+totalGraphId).parent().appendTo('.viewanalytics-total-graph');if(analytics.data){$('#'+totalGraphId).parent().show();dobrado.graph.loadData(totalGraphId,analytics.data,analytics.series);}}
if(refererGrid){refererGrid.setData(analytics.referers);refererGrid.updateRowCount();refererGrid.render();}});}}()); if(refererGrid){refererGrid.setData(analytics.referers);refererGrid.updateRowCount();refererGrid.render();}});return false;}}());
\ No newline at end of file \ No newline at end of file
...@@ -63,7 +63,8 @@ if (!this.dobrado.viewanalytics) { ...@@ -63,7 +63,8 @@ if (!this.dobrado.viewanalytics) {
{ id : "page", name: "Page", field: "page", { id : "page", name: "Page", field: "page",
width: 150, sortable: true }, width: 150, sortable: true },
{ id : "referer", name: "Referer", field: "referer", { id : "referer", name: "Referer", field: "referer",
width: 400, sortable: true }, width: 400, sortable: true,
formatter: refererFormatter },
{ id : "counter", name: "#", field: "counter", { id : "counter", name: "#", field: "counter",
width: 50, sortable: true }]; width: 50, sortable: true }];
var options = { autoHeight: true, forceFitColumns: true }; var options = { autoHeight: true, forceFitColumns: true };
...@@ -91,6 +92,11 @@ if (!this.dobrado.viewanalytics) { ...@@ -91,6 +92,11 @@ if (!this.dobrado.viewanalytics) {
setTimeout(view, 500); setTimeout(view, 500);
}); });
function refererFormatter(row, cell, value, columnDef, dataContext) {
if (value === '') return '';
return '<a href="' + value + '">' + value + '</a>';
}
function view() { function view() {
var start = parseInt($.datepicker.formatDate('@', var start = parseInt($.datepicker.formatDate('@',
$('#viewanalytics-total-start').datepicker('getDate')), 10); $('#viewanalytics-total-start').datepicker('getDate')), 10);
...@@ -123,6 +129,7 @@ if (!this.dobrado.viewanalytics) { ...@@ -123,6 +129,7 @@ if (!this.dobrado.viewanalytics) {
refererGrid.render(); refererGrid.render();
} }
}); });
return false;
} }
}()); }());
...@@ -72,7 +72,7 @@ if($.inArray(target,targetList[status])===-1){targetList[status].push(target);ur ...@@ -72,7 +72,7 @@ if($.inArray(target,targetList[status])===-1){targetList[status].push(target);ur
else{statusQuery[status]=url;}}}});$.each(statusQuery,function(status,query){var href=config[status].replace('{url}',query);var xhr=createCORSRequest(href);if(xhr){xhr.onload=function(){if(xhr.responseText){var state=JSON.parse(xhr.responseText);updateActions(state);}};xhr.withCredentials=true;xhr.send();}});} else{statusQuery[status]=url;}}}});$.each(statusQuery,function(status,query){var href=config[status].replace('{url}',query);var xhr=createCORSRequest(href);if(xhr){xhr.onload=function(){if(xhr.responseText){var state=JSON.parse(xhr.responseText);updateActions(state);}};xhr.withCredentials=true;xhr.send();}});}
function openDialog(){var config=null;if(dobrado.localStorage&&localStorage.indieConfig){config=JSON.parse(localStorage.indieConfig);} function openDialog(){var config=null;if(dobrado.localStorage&&localStorage.indieConfig){config=JSON.parse(localStorage.indieConfig);}
if(config&&actionSet(config)){return;} if(config&&actionSet(config)){return;}
$('.indie-config-info').html(indieConfigInfo).show();var text='<div><p>This page displays <b>web actions</b> that <i>link'+'back to your own website</i>, so that you can own your response.'+'<br>(You can then send a webmention to notify this site.)</p>'+'<p>If you have a website that handles web actions, you can provide '+'an address to find your web action config here:'+'<form><div class="form-spacing">'+'<label for="indie-action-handler">Address:</label>'+'<input id="indie-action-handler" type="text">'+'<button id="indie-action-submit"">submit</button>'+'</div><span id="indie-action-info"></span></form></p>'+'<p>Instead of using your own site, you can also use Quill, Twitter '+'or Facebook for web actions by clicking one of the buttons below.'+'</p>'+'<button id="indie-action-quill">Quill</button>'+'<button id="indie-action-twitter">Twitter</button>'+'<button id="indie-action-facebook">Facebook</button></div>';if($('#indie-config-dialog').length===0){$(text).attr('id','indie-config-dialog').appendTo('body');} $('.indie-config-info').html(indieConfigInfo).show();$('indie-action').each(function(){$(this).data('checked',false);});var text='<div><p>This page displays <b>web actions</b> that <i>link'+'back to your own website</i>, so that you can own your response.'+'<br>(You can then send a webmention to notify this site.)</p>'+'<p>If you have a website that handles web actions, you can provide '+'an address to find your web action config here:'+'<form><div class="form-spacing">'+'<label for="indie-action-handler">Address:</label>'+'<input id="indie-action-handler" type="text">'+'<button id="indie-action-submit"">submit</button>'+'</div><span id="indie-action-info"></span></form></p>'+'<p>Instead of using your own site, you can also use Quill, Twitter '+'or Facebook for web actions by clicking one of the buttons below.'+'</p>'+'<button id="indie-action-quill">Quill</button>'+'<button id="indie-action-twitter">Twitter</button>'+'<button id="indie-action-facebook">Facebook</button></div>';if($('#indie-config-dialog').length===0){$(text).attr('id','indie-config-dialog').appendTo('body');}
$('#indie-config-dialog').dialog({show:true,width:500,position:{my:'top',at:'top+50',of:window},title:'Web Actions',create:dobrado.fixedDialog});$('#indie-action-submit').button().click(function(){$('#indie-action-info').html('Checking...');$.post('/php/webaction.php',{url:$('#indie-action-handler').val(),token:dobrado.token},function(response){if(actionSet(response)){localStorage.indieConfig=JSON.stringify(response);handleConfig();$('#indie-action-info').html('<b>config found.</b>');setTimeout(function(){$('#indie-config-dialog').dialog('close');$('#indie-config-dialog').remove();},2000);} $('#indie-config-dialog').dialog({show:true,width:500,position:{my:'top',at:'top+50',of:window},title:'Web Actions',create:dobrado.fixedDialog});$('#indie-action-submit').button().click(function(){$('#indie-action-info').html('Checking...');$.post('/php/webaction.php',{url:$('#indie-action-handler').val(),token:dobrado.token},function(response){if(actionSet(response)){localStorage.indieConfig=JSON.stringify(response);handleConfig();$('#indie-action-info').html('<b>config found.</b>');setTimeout(function(){$('#indie-config-dialog').dialog('close');$('#indie-config-dialog').remove();},2000);}
else{$('#indie-action-info').html('<i>config was not found using '+'the address given.</i>');}});return false;});$('#indie-action-quill').button().click(function(){localStorage.indieConfig=JSON.stringify({like:'https://quill.p3k.io/favorite?url={url}',repost:'https://quill.p3k.io/repost?url={url}',reply:'https://quill.p3k.io/new?reply={url}',});$('#indie-config-dialog').dialog('close');$('#indie-config-dialog').remove();handleConfig();});$('#indie-action-twitter').button().click(function(){localStorage.indieConfig=JSON.stringify({repost:'https://twitter.com/intent/tweet?url={url}'});$('#indie-config-dialog').dialog('close');$('#indie-config-dialog').remove();handleConfig();});$('#indie-action-facebook').button().click(function(){localStorage.indieConfig=JSON.stringify({repost:'https://www.facebook.com/sharer/sharer.php?u={url}'});$('#indie-config-dialog').dialog('close');$('#indie-config-dialog').remove();handleConfig();});} else{$('#indie-action-info').html('<i>config was not found using '+'the address given.</i>');}});return false;});$('#indie-action-quill').button().click(function(){localStorage.indieConfig=JSON.stringify({like:'https://quill.p3k.io/favorite?url={url}',repost:'https://quill.p3k.io/repost?url={url}',reply:'https://quill.p3k.io/new?reply={url}',});$('#indie-config-dialog').dialog('close');$('#indie-config-dialog').remove();handleConfig();});$('#indie-action-twitter').button().click(function(){localStorage.indieConfig=JSON.stringify({repost:'https://twitter.com/intent/tweet?url={url}'});$('#indie-config-dialog').dialog('close');$('#indie-config-dialog').remove();handleConfig();});$('#indie-action-facebook').button().click(function(){localStorage.indieConfig=JSON.stringify({repost:'https://www.facebook.com/sharer/sharer.php?u={url}'});$('#indie-config-dialog').dialog('close');$('#indie-config-dialog').remove();handleConfig();});}
function webActionSettings(){var config=null;if(dobrado.localStorage&&localStorage.indieConfig){config=JSON.parse(localStorage.indieConfig);} function webActionSettings(){var config=null;if(dobrado.localStorage&&localStorage.indieConfig){config=JSON.parse(localStorage.indieConfig);}
......
...@@ -346,8 +346,9 @@ if (!this.dobrado) { ...@@ -346,8 +346,9 @@ if (!this.dobrado) {
return; return;
} }
// Reset the description on the page. // Reset the description on the page and unset indie-action checks.
$('.indie-config-info').html(indieConfigInfo).show(); $('.indie-config-info').html(indieConfigInfo).show();
$('indie-action').each(function() { $(this).data('checked', false); });
// Then load a dialog to explain what web actions are. // Then load a dialog to explain what web actions are.
var text = '<div><p>This page displays <b>web actions</b> that <i>link' + var text = '<div><p>This page displays <b>web actions</b> that <i>link' +
'back to your own website</i>, so that you can own your response.' + 'back to your own website</i>, so that you can own your response.' +
......
...@@ -174,7 +174,14 @@ if ($scope === '' && $response_type === 'code') { ...@@ -174,7 +174,14 @@ if ($scope === '' && $response_type === 'code') {
$scope = 'create'; $scope = 'create';
} }
echo '<p>' . $app_details . ' wants to log you in as <a href="' . $me . '">' . echo '<!DOCTYPE html>' . "\n" .
'<meta charset="utf-8">' . "\n" .
'<meta name="viewport" content="width=device-width">' . "\n" .
'<html><head><title>Authorisation requested</title>' . "\n" .
'<style> p { line-height: 50px; } img { width: 50px; float: left; ' .
'margin-right: 10px; } button { margin-left: 60px }' .
'</style></head>' .
'<p>' . $app_details . ' wants to log you in as <a href="' . $me . '">' .
$me . '</a></p>' . $me . '</a></p>' .
'<form action="/php/auth_endpoint.php" method="post">' . '<form action="/php/auth_endpoint.php" method="post">' .
'<input type="hidden" name="me" value="' . $me . '">' . '<input type="hidden" name="me" value="' . $me . '">' .
...@@ -186,4 +193,5 @@ echo '<p>' . $app_details . ' wants to log you in as <a href="' . $me . '">' . ...@@ -186,4 +193,5 @@ echo '<p>' . $app_details . ' wants to log you in as <a href="' . $me . '">' .
'<input type="hidden" name="token" ' . '<input type="hidden" name="token" ' .
'value="' . $_SESSION['auth-endpoint'] . '">' . 'value="' . $_SESSION['auth-endpoint'] . '">' .
'<button>Continue</button>' . '<button>Continue</button>' .
'</form>' . $redirect_info; '</form>' . $redirect_info .
\ No newline at end of file '</body></html>';
\ No newline at end of file
...@@ -131,7 +131,10 @@ function discover_endpoint($url, $rels) { ...@@ -131,7 +131,10 @@ function discover_endpoint($url, $rels) {
// Use SimplePie to cache images. // Use SimplePie to cache images.
include_once 'autoloader.php'; include_once 'autoloader.php';
$simple_pie = new SimplePie(); $simple_pie = new SimplePie();
$simple_pie->set_image_handler('/php/image.php'); $scheme = $this->user->config->Secure() ? 'https://' : 'http://';
$handler = $scheme . $this->user->config->ServerName() . '/php/image.php';
// The full image handler url is required for Microsub clients.
$simple_pie->set_image_handler($handler);
$simple_pie->init(); $simple_pie->init();
// Use the url without the scheme for more lenient matching. // Use the url without the scheme for more lenient matching.
$domain = $url; $domain = $url;
...@@ -321,7 +324,11 @@ function parse_hcard($author, $name_only = false) { ...@@ -321,7 +324,11 @@ function parse_hcard($author, $name_only = false) {
// Use SimplePie to cache images. // Use SimplePie to cache images.
include_once 'autoloader.php'; include_once 'autoloader.php';
$simple_pie = new SimplePie(); $simple_pie = new SimplePie();
$simple_pie->set_image_handler('/php/image.php'); $scheme = $this->user->config->Secure() ? 'https://' : 'http://';
$handler = $scheme . $this->user->config->ServerName() .
'/php/image.php';
// The full image handler url is required for Microsub clients.
$simple_pie->set_image_handler($handler);
$simple_pie->init(); $simple_pie->init();
$us_photo = $simple_pie->sanitize($us_photo, SIMPLEPIE_CONSTRUCT_IRI, $us_photo = $simple_pie->sanitize($us_photo, SIMPLEPIE_CONSTRUCT_IRI,
'', true); '', true);
......
...@@ -513,6 +513,7 @@ class SimplePie_Parser ...@@ -513,6 +513,7 @@ class SimplePie_Parser
if (in_array('h-entry', $entry['type']) || if (in_array('h-entry', $entry['type']) ||
in_array('h-cite', $entry['type'])) { in_array('h-cite', $entry['type'])) {
$item = array(); $item = array();
$media = array();
$title = ''; $title = '';
$description = ''; $description = '';
if (isset($entry['properties']['url'][0])) { if (isset($entry['properties']['url'][0])) {
...@@ -569,10 +570,10 @@ class SimplePie_Parser ...@@ -569,10 +570,10 @@ class SimplePie_Parser
$use_content = true; $use_content = true;
if (isset($entry['properties']['summary'][0])) { if (isset($entry['properties']['summary'][0])) {
// Use summary as content if there are any unrecognized properties. // Use summary as content if there are any unrecognized properties.
$known_properties = ['like-of', 'repost-of', 'in-reply-to', 'url', $known_properties =
'author', 'name', 'uid', 'category', 'published', array('like-of', 'repost-of', 'in-reply-to', 'url', 'author',
'summary', 'content', 'photo', 'comment', 'like', 'name', 'uid', 'category', 'published', 'summary', 'content',
'repost']; 'photo', 'comment', 'like', 'repost');
foreach ($entry['properties'] as $name => $property) { foreach ($entry['properties'] as $name => $property) {
if (!in_array($name, $known_properties)) { if (!in_array($name, $known_properties)) {
$use_content = false; $use_content = false;
...@@ -598,6 +599,7 @@ class SimplePie_Parser ...@@ -598,6 +599,7 @@ class SimplePie_Parser
} }
$description .= $entry['properties']['content'][0]['html']; $description .= $entry['properties']['content'][0]['html'];
} }
// Images, audio and video are all stored using Media RSS.
if (isset($entry['properties']['photo'][0])) { if (isset($entry['properties']['photo'][0])) {
$photo_list = array(); $photo_list = array();
foreach ($entry['properties']['photo'] as $photo) { foreach ($entry['properties']['photo'] as $photo) {
...@@ -612,23 +614,66 @@ class SimplePie_Parser ...@@ -612,23 +614,66 @@ class SimplePie_Parser
$description = '<div class="photo-hidden">' . $description.'</div>'; $description = '<div class="photo-hidden">' . $description.'</div>';
$photo_list = $entry['properties']['photo']; $photo_list = $entry['properties']['photo'];
} }
$count = count($photo_list); foreach ($photo_list as $photo) {
if ($count > 1) { // Find the type of image.
// When there's more than one photo show the first two and use a if (preg_match('/\.([a-z]+)$/', strtolower($photo), $match)) {
// lightbox. Need a permanent, unique name for the image set, but $type = '';
// don't have anything unique except for photo urls, so use that. if (in_array($match[1], array('gif', 'jpeg', 'png'))) {
$image_set_id = preg_replace('/[[:^alnum:]]/', '', $photo_list[0]); $type = 'image/' . $match[1];
$description .= '<p class="photo-list">'; }
for ($i = 0; $i < $count; $i++) { else if ($match[1] === 'jpg') {
$hidden = $i <= 1 ? '' : 'class="hidden" '; $type = 'image/jpeg';
$description .= '<a href="' . $photo_list[$i] . '" ' . $hidden . }
'data-lightbox="image-set-' . $image_set_id . '">' . else if ($match[1] === 'svg') {
'<img src="' . $photo_list[$i] . '"></a>'; $type = 'image/svg+xml';
}
else {
continue;
}
// The format used here is for Media RSS below.
$media[] = array('attribs' => array('' =>
array('url' => $photo, 'type' => $type)));
}
}
}
if (isset($entry['properties']['audio'][0])) {
foreach ($entry['properties']['audio'] as $audio) {
if (preg_match('/\.([a-z]+)$/', strtolower($audio), $match)) {
$type = '';
$audio_types = array('aac', 'mpeg', 'ogg', 'wav', 'webm');
if (in_array($match[1], $audio_types)) {
$type = 'audio/' . $match[1];
}
else if ($match[1] === 'mp3') {
$type = 'audio/mpeg';
}
else if ($match[1] === 'oga') {
$type = 'audio/ogg';
}
else {
continue;
}
$media[] = array('attribs' => array('' =>
array('url' => $audio, 'type' => $type)));
} }
$description .= '<br><b>' . $count . ' photos</b></p>';
} }
else if ($count == 1) { }
$description .= '<p><img src="' . $photo_list[0] . '"></p>'; if (isset($entry['properties']['video'][0])) {
foreach ($entry['properties']['video'] as $video) {
if (preg_match('/\.([a-z]+)$/', strtolower($video), $match)) {
$type = '';
if (in_array($match[1], array('mp4', 'webm'))) {
$type = 'video/' . $match[1];
}
else if ($match[1] === 'ogv') {
$type = 'video/ogg';
}
else {
continue;
}
$media[] = array('attribs' => array('' =>
array('url' => $video, 'type' => $type)));
}
} }
} }
if (isset($entry['properties']['like-of'][0])) { if (isset($entry['properties']['like-of'][0])) {
...@@ -674,19 +719,18 @@ class SimplePie_Parser ...@@ -674,19 +719,18 @@ class SimplePie_Parser
$item['description'] = array(array('data' => $description)); $item['description'] = array(array('data' => $description));
} }
if (isset($entry['properties']['category'])) { if (isset($entry['properties']['category'])) {
$category_csv = ''; $category_list = array();
// Categories can also contain h-cards. // Categories can also contain h-cards.
foreach ($entry['properties']['category'] as $category) { foreach ($entry['properties']['category'] as $category) {
if ($category_csv !== '') $category_csv .= ', ';
if (is_string($category)) { if (is_string($category)) {
// Can't have commas in categories. $category_list[] = array('data' => $category);
$category_csv .= str_replace(',', '', $category);
} }
else { else {
$category_csv .= $this->parse_hcard($category, true); $category_list[] =
array('data' => $this->parse_hcard($category, true));
} }
} }
$item['category'] = array(array('data' => $category_csv)); $item['category'] = array($category_list);
} }
if (isset($entry['properties']['published'][0])) { if (isset($entry['properties']['published'][0])) {
$timestamp = strtotime($entry['properties']['published'][0]); $timestamp = strtotime($entry['properties']['published'][0]);
...@@ -699,7 +743,8 @@ class SimplePie_Parser ...@@ -699,7 +743,8 @@ class SimplePie_Parser
$item['title'] = array(array('data' => '')); $item['title'] = array(array('data' => ''));
$item['description'] = array(array('data' => '')); $item['description'] = array(array('data' => ''));
} }
$items[] = array('child' => array('' => $item)); $items[] = array('child' => array('' => $item,
SIMPLEPIE_NAMESPACE_MEDIARSS => array('content' => array($media))));
} }
} }
// Mimic RSS data format when storing microformats. // Mimic RSS data format when storing microformats.
......
...@@ -32,14 +32,17 @@ function curl($url) { ...@@ -32,14 +32,17 @@ function curl($url) {
} }
if (!isset($_GET['url']) || $_GET['url'] === '') { if (!isset($_GET['url']) || $_GET['url'] === '') {
echo '<html><head><title>Microformats parser</title>' . echo '<!DOCTYPE html>' . "\n" .
'<meta charset="utf-8">' . "\n" .
'<meta name="viewport" content="width=device-width">' . "\n" .
'<html><head><title>Microformats parser</title>' . "\n" .
'<style>.form-spacing { margin: 4px; clear: both; }' . '<style>.form-spacing { margin: 4px; clear: both; }' .
'.form-spacing > input[type=text] { height: 25px; width: 300px }' . '.form-spacing > input[type=text] { height: 25px; width: 300px }' .
'.form-spacing > input[type=checkbox] { height: 20px; }' . '.form-spacing > input[type=checkbox] { height: 20px; }' .
'.form-spacing > label { float: left; margin-top: 0.3em; ' . '.form-spacing > label { float: left; margin-top: 0.3em; ' .
'margin-right: 0.3em; text-align: right; width: 6em; } ' . 'margin-right: 0.3em; text-align: right; width: 6em; } ' .
'button { margin-left: 7.1em; } ' . 'button { margin-left: 7.1em; } ' .
'</style></head>' . '</style></head><body>' . "\n" .
'<p>Enter a url to parse microformats found at that address. Options:<ul>' . '<p>Enter a url to parse microformats found at that address. Options:<ul>' .
'<li><b>item</b> returns only the data at the selected index.</li>' . '<li><b>item</b> returns only the data at the selected index.</li>' .
'<li><b>property</b> used with item returns only this property.</li>' . '<li><b>property</b> used with item returns only this property.</li>' .
...@@ -59,7 +62,7 @@ if (!isset($_GET['url']) || $_GET['url'] === '') { ...@@ -59,7 +62,7 @@ if (!isset($_GET['url']) || $_GET['url'] === '') {
'<label>curl:</label><input type="checkbox" name="curl">' . '<label>curl:</label><input type="checkbox" name="curl">' .
'</div>' . '</div>' .
'<button>submit</button>' . '<button>submit</button>' .
'</form>'; '</form></body></html>';
exit; exit;
} }
......
...@@ -66,6 +66,8 @@ function photo_html($photo_list) { ...@@ -66,6 +66,8 @@ function photo_html($photo_list) {
return $html . '<br><b>' . $count . ' photos</b></p>'; return $html . '<br><b>' . $count . ' photos</b></p>';
} }
include 'functions/db.php';
$us_token = ''; $us_token = '';
$headers = apache_request_headers(); $headers = apache_request_headers();
$content_type = header_value($headers, 'Content-Type'); $content_type = header_value($headers, 'Content-Type');
...@@ -107,8 +109,6 @@ else { ...@@ -107,8 +109,6 @@ else {
exit; exit;
} }
include 'functions/db.php';
$me = ''; $me = '';
$mysqli = connect_db(); $mysqli = connect_db();
$token = $mysqli->escape_string($us_token); $token = $mysqli->escape_string($us_token);
......
...@@ -33,7 +33,7 @@ if (isset($_POST['code'])) { ...@@ -33,7 +33,7 @@ if (isset($_POST['code'])) {
$mysqli->escape_string(strtolower(trim($_POST['client_id'], ' /'))); $mysqli->escape_string(strtolower(trim($_POST['client_id'], ' /')));
$redirect_uri = $redirect_uri =
$mysqli->escape_string(strtolower(trim($_POST['redirect_uri'], ' /'))); $mysqli->escape_string(strtolower(trim($_POST['redirect_uri'], ' /')));
$us_me = $_POST['me']; $us_me = strtolower(trim($_POST['me'], ' /'));
$me = $mysqli->escape_string($us_me); $me = $mysqli->escape_string($us_me);
// This query can be used twice, firstly to match an entry using the // This query can be used twice, firstly to match an entry using the
// parameters provided and then to remove it as it should only be used once. // parameters provided and then to remove it as it should only be used once.
...@@ -41,7 +41,7 @@ if (isset($_POST['code'])) { ...@@ -41,7 +41,7 @@ if (isset($_POST['code'])) {
'AND client_id = "' . $client_id . '" AND ' . 'AND client_id = "' . $client_id . '" AND ' .
'redirect_uri = "' . $redirect_uri . '" AND response_type = "code"'; 'redirect_uri = "' . $redirect_uri . '" AND response_type = "code"';
$query = 'SELECT scope FROM auth_codes ' . $auth_codes_query . $query = 'SELECT scope FROM auth_codes ' . $auth_codes_query .
'AND timestamp > ' . time(); ' AND timestamp > ' . time();
if ($result = $mysqli->query($query)) { if ($result = $mysqli->query($query)) {
if ($auth_codes = $result->fetch_assoc()) { if ($auth_codes = $result->fetch_assoc()) {
$us_scope = $auth_codes['scope']; $us_scope = $auth_codes['scope'];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment