Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(podcastindex): expose guid as href attribute on podcast:person tag #1195

Open
wants to merge 7 commits into
base: beta
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions includes/scripts_and_styles.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@
'jquery', 'jquery-ui-sortable', 'jquery-ui-datepicker',
], $version);

wp_localize_script(
'podlove_admin',
'podlove_vue',
[
'rest_url' => esc_url_raw(rest_url()),
'nonce' => wp_create_nonce('wp_rest')
]
);

wp_enqueue_style('jquery-ui-style', \Podlove\PLUGIN_URL.'/js/admin/jquery-ui/css/smoothness/jquery-ui.css');
}
});
128 changes: 124 additions & 4 deletions js/src/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,93 @@ function convert_to_slug(string) {
return string;
}

function fix_url(string) {
if (!string) {
return null;
}
var url = string;
try { url = new URL(string) }
catch { url = new URL((string.indexOf("@") != -1 ? 'acct:' : 'https://') + string) };
if ( url.protocol === 'http:' ) {
url.protocol = 'https:'
}
return PODLOVE.untrailingslashit(url.toString());
}


function lookup_identifier(service, id) {
try {
return jQuery.getJSON(podlove_vue.rest_url + "podlove/v1/social/lookup/" + service, {'id': id })
// returns 404 when nothing is found,
// TODO: how to I supress the error message in the browser's JavaScript Console?
}
catch { }
}

function auto_fill_form(id, title_id) {
(function ($) {
function find_profile(identifier, type) {
// identier is probably an URI
if ( type !== 'email' && identifier.indexOf(":") !== -1 ) {
lookup_identifier('webfinger', identifier).done(function(webfinger) {
console.debug("webfinger lookup response", webfinger);
fill_if_empty('#podlove_contributor_guid', webfinger.subject);
fill_if_empty('#podlove_contributor_privateemail', webfinger.alias);

// TODO: Add social media accounts from webfinger.aliases to datatable
fill_person_from_links(webfinger.links);
});
return null;
}
// identier is probably a string in form user@domain.tld
else {
lookup_identifier('webfinger', 'acct:' + identifier).done((webfinger) => {
console.debug("webfinger lookup response", webfinger);
if (webfinger) {
// allways overwrite URI with subject from response
$('#podlove_contributor_guid').val(webfinger.subject);
// TODO: Add social media accounts from webfinger.aliases to datatable
fill_person_from_links(webfinger.links);
}
}).fail(() => lookup_identifier('gravatar.com', identifier).done((gravatar) => {
console.debug("gravatar lookup response", gravatar);
fill_if_empty('#podlove_contributor_guid', fix_url(gravatar.urls?.[0]?.value || gravatar.accounts?.pop()?.url || 'https://' + identifier.split('@')[1]));
fill_if_empty('#podlove_contributor_identifier', gravatar.preferredUsername);
fill_if_empty('#podlove_contributor_realname', gravatar.name.formatted
|| [gravatar.name.givenName, gravatar.name.familyName].join(' ')
|| gravatar.preferredUsername);
fill_if_empty('#podlove_contributor_publicname', gravatar.name.formatted || gravatar.preferredUsername);
fill_if_empty('#podlove_contributor_avatar', gravatar.thumbnailUrl, true);
}));
}
}

function fill_person_from_links(links) {
// lookup links[rel=self] for name, avatar, etc.
var self = links.filter(x => x.rel === 'self');
if (self.length > 0) {
lookup_identifier('json', self[0].href).done((mastodon) => {
console.debug("links.self person lookup response", mastodon);
fill_if_empty('#podlove_contributor_identifier', mastodon.preferredUsername);
fill_if_empty('#podlove_contributor_realname', mastodon.name || mastodon.preferredUsername);
fill_if_empty('#podlove_contributor_publicname', mastodon.name || mastodon.preferredUsername);
fill_if_empty('#podlove_contributor_avatar', mastodon.icon.url, true);
});
}
}

function fill_if_empty(field, value, triggerChangeEvent) {
var input = $(field);
if ( input.val() == "" && value ) {
input.val(value);
if (triggerChangeEvent) {
input.change();
}
return true;
}
}


switch (id) {
case 'contributor':
if ($("#podlove_contributor_publicname").val() == "") {
Expand All @@ -102,6 +187,27 @@ function auto_fill_form(id, title_id) {
$("#podlove_contributor_publicname").attr('placeholder', $("#podlove_contributor_realname").val());
}
}
if ($("#podlove_contributor_guid").val() == "") {
if ($("#podlove_contributor_realname").val() != "") {
$("#podlove_contributor_publicname").attr('placeholder', $("#podlove_contributor_nickname").val());
}
}
break;
case 'contributor_email':
if ($("#podlove_contributor_avatar").val() == "") {
var email = $("#podlove_contributor_privateemail").val();
if (email != "") {
find_profile(email, 'email');
}
}
break;
case 'contributor_guid':
if ($("#podlove_contributor_avatar").val() == "") {
var guid = $("#podlove_contributor_guid").val();
if (guid != "") {
find_profile(guid, 'uri');
}
}
break;
case 'contributor_group':
if ($("#podlove_contributor_group_slug").val() == "") {
Expand Down Expand Up @@ -155,6 +261,9 @@ function clean_up_input() {

textfield.addClass("podlove-invalid-input");
$status.addClass("podlove-input-isinvalid");

// abort further change events, hopefully
return false;
}

// trim whitespace
Expand Down Expand Up @@ -182,7 +291,7 @@ function clean_up_input() {
if (!textfield.val().match(valid_url_regexp)) {
// Encode URL only if it is not already encoded
if (!encodeURI(textfield.val()).match(valid_url_regexp)) {
ShowInputError('Please enter a valid URL');
return ShowInputError('Please enter a valid URL');
} else {
textfield.val(encodeURI(textfield.val()));
}
Expand All @@ -193,13 +302,13 @@ function clean_up_input() {
// textfield.val( encodeURI( textfield.val() ) );

if (!textfield.val().match(/^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/i)) {
ShowInputError('Please enter a valid email adress or a valid URL');
return ShowInputError('Please enter a valid email adress or a valid URL');
}
}
break;
case "email":
if (!textfield.val().match(/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/i))
ShowInputError('Please enter a valid email adress.');
if (!textfield.val().match(/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/i))
return ShowInputError('Please enter a valid email adress.');
break;
}
}
Expand Down Expand Up @@ -286,6 +395,10 @@ jQuery(function ($) {
auto_fill_form('contributor', 'realname');
});

$("#podlove_contributor_privateemail").change(function () {
auto_fill_form('contributor_email', 'email');
});

$("#podlove_contributor_group_title").change(function () {
auto_fill_form('contributor_group', 'group_title');
});
Expand All @@ -296,9 +409,16 @@ jQuery(function ($) {

$(document).ready(function () {
auto_fill_form('contributor', 'realname');
// TODO auto_fill_form('contributor_guid', 'guid'); from social media accounts
clean_up_input();
init_contextual_help_links();
new ClipboardJS('.clipboard-btn');
});

const guid = $("#podlove_contributor_guid");
guid.change(function () {
guid.val(fix_url(guid.val()));
auto_fill_form('contributor_guid', 'guid');
});

});
2 changes: 1 addition & 1 deletion lib/feeds/base.php
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ function override_feed_entry($hook, $podcast, $feed, $format)
$xml .= ob_get_contents();
ob_end_clean();

return $xml;
return $xml . "\n";
}, 15 * MINUTE_IN_SECONDS);
}, 11);
}
10 changes: 6 additions & 4 deletions lib/modules/contributors/contributors.php
Original file line number Diff line number Diff line change
Expand Up @@ -925,7 +925,7 @@ private function getContributorXML($contributor)

$dom->appendChild($xml);

$contributor_xml .= (string) $dom;
$contributor_xml .= "\n\t\t" . trim((string) $dom);
}

return $contributor_xml;
Expand All @@ -934,8 +934,6 @@ private function getContributorXML($contributor)
/**
* get contributor xml in podcastindex "person" format.
*
* @todo take first social URL and add it as href attribute
*
* @see https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md#person
*
* @param mixed $contributor
Expand All @@ -955,6 +953,10 @@ private function getPodcastindexContributorXML($contributor, $contribution)

$dom->appendChild($xml);

if ($contributor->guid) {
$xml->appendChild($xml->setAttribute('href', $contributor->guid));
}

$xml->setAttribute('img', $contributor->avatar()->url());

// proof of concept for roles/groups
Expand Down Expand Up @@ -987,7 +989,7 @@ private function getPodcastindexContributorXML($contributor, $contribution)
}
}

$contributor_xml .= (string) $dom;
$contributor_xml .= "\n\t\t" . trim((string) $dom);
}

return $contributor_xml;
Expand Down
38 changes: 19 additions & 19 deletions lib/modules/contributors/settings/tab/contributors.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,22 @@ public function createObject()
private function contributor_form($form_args, $contributor, $action)
{
$general_fields = [
'privateemail' => [
'field_type' => 'string',
'field_options' => [
'label' => __('Contact email', 'podlove-podcasting-plugin-for-wordpress'),
'description' => __('The provided email will be used for internal purposes only.', 'podlove-podcasting-plugin-for-wordpress'),
'html' => ['class' => 'podlove-contributor-field podlove-check-input', 'data-podlove-input-type' => 'email'],
],
],
'guid' => [
'field_type' => 'string',
'field_options' => [
'label' => __('URI', 'podlove-podcasting-plugin-for-wordpress'),
'description' => __('A globally unique identifier to match contributors across podcasts on the internet, <br/> e.g. URL of contributor’s personal home page or social media profile.', 'podlove-podcasting-plugin-for-wordpress'),
'html' => ['class' => 'podlove-check-input podlove-contributor-field', 'data-podlove-input-type' => 'url'],
],
],
'realname' => [
'field_type' => 'string',
'field_options' => [
Expand All @@ -110,22 +126,14 @@ private function contributor_form($form_args, $contributor, $action)
'field_type' => 'select',
'field_options' => [
'label' => __('Gender', 'podlove-podcasting-plugin-for-wordpress'),
'options' => ['female' => 'Female', 'male' => 'Male', 'none' => 'Not attributed'],
],
],
'privateemail' => [
'field_type' => 'string',
'field_options' => [
'label' => __('Contact email', 'podlove-podcasting-plugin-for-wordpress'),
'description' => __('The provided email will be used for internal purposes only.', 'podlove-podcasting-plugin-for-wordpress'),
'html' => ['class' => 'podlove-contributor-field podlove-check-input', 'data-podlove-input-type' => 'email'],
'options' => ['female' => 'Female', 'male' => 'Male', 'other' => 'Other', 'none' => 'Not attributed'],
],
],
'avatar' => [
'field_type' => 'upload',
'field_options' => [
'label' => __('Avatar', 'podlove-podcasting-plugin-for-wordpress'),
'description' => __('Either a Gravatar email adress or a URL.', 'podlove-podcasting-plugin-for-wordpress'),
'description' => __('Either a Gravatar email address or a URL.', 'podlove-podcasting-plugin-for-wordpress'),
'html' => [
'class' => 'podlove-contributor-field podlove-check-input',
'data-podlove-input-type' => 'avatar',
Expand All @@ -136,19 +144,11 @@ private function contributor_form($form_args, $contributor, $action)
'identifier' => [
'field_type' => 'string',
'field_options' => [
'label' => __('ID', 'podlove-podcasting-plugin-for-wordpress'),
'label' => __('Template ID', 'podlove-podcasting-plugin-for-wordpress'),
'description' => __('The ID will be used as in internal identifier for e.g. shortcodes.', 'podlove-podcasting-plugin-for-wordpress'),
'html' => ['class' => 'podlove-check-input required podlove-contributor-field'],
],
],
'guid' => [
'field_type' => 'string',
'field_options' => [
'label' => __('URI', 'podlove-podcasting-plugin-for-wordpress'),
'description' => __('An URI acts as a globally unique ID to identify contributors across podcasts on the internet.', 'podlove-podcasting-plugin-for-wordpress'),
'html' => ['class' => 'podlove-check-input podlove-contributor-field'],
],
],
'visibility' => [
'field_type' => 'radio',
'field_options' => [
Expand Down
Loading