Browse Source

enables webmention sending forms from dashboard

pull/3/head
Aaron Parecki 8 years ago
parent
commit
3d045909a4
9 changed files with 274 additions and 33 deletions
  1. +2
    -1
      composer.json
  2. +52
    -2
      composer.lock
  3. +1
    -0
      controllers/API.php
  4. +64
    -14
      controllers/Controller.php
  5. +7
    -0
      lib/helpers.php
  6. +1
    -0
      public/index.php
  7. +72
    -9
      views/dashboard.php
  8. +7
    -0
      views/webmention-details.php
  9. +68
    -7
      views/webmention-send.php

+ 2
- 1
composer.json View File

@ -9,7 +9,8 @@
"league/route": "~1.2",
"league/plates": "~3.1",
"j4mie/idiorm": "1.5.*",
"p3k/caterpillar": "0.1.*"
"p3k/caterpillar": "0.1.*",
"predis/predis": "1.*"
},
"require-dev": {
"phpunit/phpunit": "*"

+ 52
- 2
composer.lock View File

@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "f093ab92ae4ced25546dcff30639c5d9",
"content-hash": "61bdf94447ac95a334eb26e591a7b4e3",
"hash": "608bb1b12f4959a9b2dccdd64046ac57",
"content-hash": "eefd85cb3d0c9cf1666ed057a450544d",
"packages": [
{
"name": "barnabywalters/mf-cleaner",
@ -671,6 +671,56 @@
],
"time": "2015-08-07 21:42:41"
},
{
"name": "predis/predis",
"version": "v1.0.3",
"source": {
"type": "git",
"url": "https://github.com/nrk/predis.git",
"reference": "84060b9034d756b4d79641667d7f9efe1aeb8e04"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nrk/predis/zipball/84060b9034d756b4d79641667d7f9efe1aeb8e04",
"reference": "84060b9034d756b4d79641667d7f9efe1aeb8e04",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"suggest": {
"ext-curl": "Allows access to Webdis when paired with phpiredis",
"ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol"
},
"type": "library",
"autoload": {
"psr-4": {
"Predis\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Daniele Alessandri",
"email": "suppakilla@gmail.com",
"homepage": "http://clorophilla.net"
}
],
"description": "Flexible and feature-complete PHP client library for Redis",
"homepage": "http://github.com/nrk/predis",
"keywords": [
"nosql",
"predis",
"redis"
],
"time": "2015-07-30 18:34:15"
},
{
"name": "symfony/http-foundation",
"version": "v2.8.0",

+ 1
- 0
controllers/API.php View File

@ -15,6 +15,7 @@ class API {
foreach($headers as $k=>$v) {
$response->headers->set($k, $v);
}
$response->headers->set('Content-Type', 'application/json');
$response->setContent(json_encode($params));
return $response;
}

+ 64
- 14
controllers/Controller.php View File

@ -47,6 +47,22 @@ class Controller {
return $response;
}
private static function _icon_for_status($status) {
switch($status) {
case 'success':
case 'accepted':
return 'green checkmark';
case 'not_supported':
return 'yellow x';
case 'error':
return 'red x';
case 'pending':
return 'orange wait';
default:
return '';
}
}
public function dashboard(Request $request, Response $response) {
if(!$this->_is_logged_in($request, $response)) {
return $response;
@ -67,23 +83,11 @@ class Controller {
foreach($query as $m) {
$statuses = ORM::for_table('webmention_status')->where('webmention_id', $m->id)->order_by_desc('created_at')->find_many();
if(count($statuses) == 0) {
$icon = 'wait';
$status = 'pending';
} else {
$status = $statuses[0]->status;
switch($status) {
case 'success':
case 'accepted':
$icon = 'checkmark';
break;
case 'not_supported':
case 'error':
$icon = 'warning';
break;
default:
$icon = '';
}
}
$icon = self::_icon_for_status($status);
$webmentions[] = [
'webmention' => $m,
@ -98,6 +102,7 @@ class Controller {
'user' => $this->_user(),
'accounts' => $this->_accounts(),
'site' => $site,
'role' => $role,
'webmentions' => $webmentions
]));
return $response;
@ -120,13 +125,22 @@ class Controller {
$statuses = ORM::for_table('webmention_status')->where('webmention_id', $webmention->id)->order_by_desc('created_at')->find_many();
if(count($statuses) == 0) {
$status = 'pending';
} else {
$status = $statuses[0]->status;
}
$icon = self::_icon_for_status($status);
$response->setContent(view('webmention-details', [
'title' => 'Webmention Details',
'user' => $this->_user(),
'accounts' => $this->_accounts(),
'site' => $site,
'webmention' => $webmention,
'statuses' => $statuses
'statuses' => $statuses,
'icon' => $icon,
'status' => $status
]));
return $response;
}
@ -173,6 +187,42 @@ class Controller {
return $response;
}
public function discover_endpoint(Request $request, Response $response) {
if(!$this->_is_logged_in($request, $response)) {
return $response;
}
$targetURL = $request->get('target');
// Cache the discovered result
$cacheKey = 'telegraph:discover_endpoint:'.$targetURL;
if($request->get('ignore_cache') == 'true' || (!$status = redis()->get($cacheKey))) {
$client = new IndieWeb\MentionClient();
$endpoint = $client->discoverWebmentionEndpoint($targetURL);
if($endpoint) {
$status = 'webmention';
} else {
$endpoint = $client->discoverPingbackEndpoint($targetURL);
if($endpoint) {
$status = 'pingback';
} else {
$status = 'none';
}
}
$cached = false;
redis()->setex($cacheKey, 600, $status);
} else {
$cached = true;
}
$response->headers->set('Content-Type', 'application/json');
$response->setContent(json_encode([
'status' => $status,
'cached' => $cached
]));
return $response;
}
private function _user() {
return ORM::for_table('users')->where_id_is(session('user_id'))->find_one();
}

+ 7
- 0
lib/helpers.php View File

@ -25,6 +25,13 @@ function q() {
return $caterpillar;
}
function redis() {
static $client = false;
if(!$client)
$client = new Predis\Client('tcp://127.0.0.1:6379');
return $client;
}
function random_string($len) {
$charset='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$str = '';

+ 1
- 0
public/index.php View File

@ -13,6 +13,7 @@ $router->addRoute('GET', '/api', 'Controller::api');
$router->addRoute('GET', '/webmention/{code}/details', 'Controller::webmention_details');
$router->addRoute('GET', '/dashboard/send', 'Controller::dashboard_send');
$router->addRoute('POST', '/dashboard/get_outgoing_links.json', 'Controller::get_outgoing_links');
$router->addRoute('POST', '/dashboard/discover_endpoint.json', 'Controller::discover_endpoint');
$router->addRoute('POST', '/webmention', 'API::webmention');
$router->addRoute('GET', '/webmention/{code}', 'API::webmention_status');

+ 72
- 9
views/dashboard.php View File

@ -2,13 +2,31 @@
<div class="ui main text container" style="margin-top: 80px;">
<form action="/dashboard/send" method="get">
<div class="ui fluid action input">
<input type="url" name="url" placeholder="enter a URL" value="https://aaronparecki.com/articles/2015/10/05/1/fun-with-qr-codes">
<button class="ui button">Send Webmentions</button>
</div>
<input type="hidden" name="account" value="<?= $site->id ?>">
</form>
<div class="ui top attached tabular menu">
<a class="item active" data-tab="send-from-source">Find Links</a>
<a class="item" data-tab="send-source-target">Send Webmention</a>
</div>
<div class="ui bottom attached tab segment active" data-tab="send-from-source">
<form action="/dashboard/send" method="get" class="ui form">
<div class="ui fluid action input">
<input type="url" name="url" placeholder="http://example.com/">
<button class="ui button">Find Links</button>
</div>
<input type="hidden" name="account" value="<?= $site->id ?>">
</form>
<div style="padding: 6px;">Enter a URL above to preview and send webmentions from all the links found on the page.</div>
</div>
<div class="ui bottom attached tab segment" data-tab="send-source-target">
<form class="ui form" id="send-webmention-form">
<div class="two fields">
<div class="field"><label>Source URL</label><input type="url" placeholder="Source URL" id="send-source"></div>
<div class="field"><label>Target URL</label><input type="url" placeholder="Target URL" id="send-target"></div>
</div>
<div class="ui error message"></div>
<button class="ui button right floated" id="send-webmention-btn">Send Webmention</button>
<div style="clear:both;"></div>
</form>
</div>
<table class="ui striped single line table">
<thead>
@ -19,8 +37,18 @@
<tbody>
<?php foreach($webmentions as $mention): ?>
<tr<?= $mention['status'] == 'pending' ? ' class="warning"' : '' ?>>
<td><i class="<?= $mention['icon'] ?> icon"></i></td>
<td><a href="/webmention/<?= $mention['webmention']->token ?>/details"><?= date('M j, g:ia', strtotime($mention['webmention']->created_at)) ?></a></td>
<td>
<div class="popup" data-content="<?= $mention['status'] ?>">
<a href="/webmention/<?= $mention['webmention']->token ?>/details">
<i class="circular inverted <?= $mention['icon'] ?> icon"></i>
</a>
</div>
</td>
<td>
<a href="/webmention/<?= $mention['webmention']->token ?>/details">
<?= date('M j, g:ia', strtotime($mention['webmention']->created_at)) ?>
</a>
</td>
<td>
source=<a href="<?= $this->e($mention['webmention']->source) ?>"><?= $this->e($mention['webmention']->source) ?></a><br>
target=<a href="<?= $this->e($mention['webmention']->source) ?>"><?= $this->e($mention['webmention']->target) ?></a>
@ -30,3 +58,38 @@
</tbody>
</table>
</div>
<script>
$(function(){
var token = "<?= $role->token ?>";
$(".tabular.menu .item").tab();
$(".popup").popup();
$("#send-webmention-btn").click(function(){
$("#send-webmention-btn").addClass("loading");
$("#send-webmention-form").removeClass("error");
// Send the request to the API now, and then redirect to the status page
$.ajax({
url: "/webmention",
method: "POST",
data: {
token: token,
source: $("#send-source").val(),
target: $("#send-target").val()
},
success: function(data){
$("#send-webmention-btn").removeClass("loading");
window.location = data.location+"/details";
},
error: function(data){
$("#send-webmention-btn").removeClass("loading");
$("#send-webmention-form").addClass("error");
$("#send-webmention-form .error.message").text(data.responseJSON.error_description);
}
});
return false;
});
});
</script>

+ 7
- 0
views/webmention-details.php View File

@ -5,6 +5,13 @@
<h2>Webmention Request</h2>
<table class="ui table single line"><tbody>
<tr>
<td><b>Status</b></td>
<td>
<i class="circular inverted <?= $icon ?> icon"></i>
<?= ucfirst($status) ?>
</td>
</tr>
<tr>
<td><b>Date</b></td>
<td><?= date('M j, g:ia', strtotime($webmention->created_at)) ?></td>

+ 68
- 7
views/webmention-send.php View File

@ -16,31 +16,92 @@
</div>
<script>
var url = "<?= $url ?>";
var source_url = "<?= $url ?>";
var token = "<?= $role->token ?>";
$(function(){
$.post('/dashboard/get_outgoing_links.json', {
url: url
url: source_url
}, function(data) {
$("#send-table tbody").html('<tr><td colspan="2"></td></tr>');
for(var i in data.links) {
console.log(data.links[i]);
$("#send-table tr:last").after('<tr>'
$("#send-table tr:last").after('<tr data-url="'+data.links[i]+'">'
+'<td class="target-url">'
+'<div class="popup" data-content="'+data.links[i]+'">'+data.links[i]+'</div>'
+'<div class="popup" data-content="'+data.links[i]+'"><span>'+data.links[i]+'<span></div>'
+'</td>'
+'<td class="send">'
+'<div class="ui active mini inline loader"></div>'
+'</td>'
+'<td><button class="ui button">Send</button></td>'
+'</tr>');
}
$("#send-table tbody tr:first").remove();
$(".popup").popup();
// Enable popup on any values that overflowed the container
$(".popup").each(function(i,el){
if($(el).children("span").width() > $(el).width()) {
$(el).popup();
}
});
// Check for a webmention or pingback endpoint
$("#send-table tr").each(function(i,el){
discover_endpoint(el, false);
});
});
});
function discover_endpoint(row, ignore_cache) {
$.post("/dashboard/discover_endpoint.json", {
target: $(row).data("url"),
ignore_cache: ignore_cache
}, function(data){
var html;
if(data.status == 'none') {
html = '<div class="ui yellow horizontal label">No endpoint found</div><br><button class="send-button check-again ui button">Check Again</button>';
} else if(data.status == 'webmention') {
html = '<button class="send-button send-now ui primary button">Send Webmention</button>';
} else if(data.status == 'pingback') {
html = '<button class="send-button send-now ui primary button">Send Pingback</button>';
}
$(row).children(".send").html(html);
bind_send_buttons();
});
}
function bind_send_buttons() {
$(".send-button").unbind("click");
$(".check-again").bind("click", function(){
var row = $(this).parents("tr");
$(row).find(".send-button").addClass('loading');
discover_endpoint(row, true);
});
$(".send-now").bind("click", function(){
var row = $(this).parents("tr");
$(row).find(".send-button").addClass('loading');
// Send to the API
$.post("/webmention", {
token: token,
source: source_url,
target: $(row).data("url")
}, function(data){
$(row).find(".send-button").removeClass('loading');
if(data.status == 'queued') {
$(row).find(".send").html('<a href="'+data.location+'/details" data-status="'+data.location+'"><i class="circular inverted orange wait icon"></i></a>');
// TODO: check for status updates on a timer
} else {
$(row).find(".send").html('<i class="circular inverted red x icon"></i>');
}
});
});
}
</script>
<style type="text/css">
.popup {
word-wrap: break-word;
}
#send-table tr {
height: 83px;
}
</style>

Loading…
Cancel
Save