Commit 3552d005 authored by Evan Goldenberg's avatar Evan Goldenberg Committed by Francois Marier
Browse files

add atom feeds for public blogs



- use the mahara logo if the user has no profile icon set
- use the user's personal website as the author uri, if set
- add a generator to indicate that the feed was generated by Mahara
- set the icon element to use favicon.ico
- set feed rights based on presence or lack of CC block in view
- display feed icon in the view if the view is public

(partial implementation of Eduforge Feature Request #3357)
Signed-off-by: default avatarEvan Goldenberg <evang@catalyst.net.nz>
Signed-off-by: default avatarFrancois Marier <francois@catalyst.net.nz>
parent 760cc82b
<?php
/**
* Mahara: Electronic portfolio, weblog, resume builder and social networking
* Copyright (C) 2006-2010 Catalyst IT Ltd and others; see:
* http://wiki.mahara.org/Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*
* @package mahara
* @subpackage artefact-blog
* @author Catalyst IT Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL
* @copyright (C) 2006-2010 Catalyst IT Ltd http://catalyst.net.nz
*
*/
define('INTERNAL', 1);
define('PUBLIC', 1);
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
define('POSTCOUNT', 20); // number of posts to include in the feed
function atom_date($date) {
$date = str_replace(' ', 'T', $date);
$date .= date('P');
return $date;
}
function generate_feed($feed, $posts) {
$smarty = smarty();
$smarty->assign('feed', $feed);
$smarty->assign('posts', $posts);
header("Content-Type: application/atom+xml");
$smarty->display('artefact:blog:atom.xml.tpl');
}
function error_feed() {
return array(
'title' => get_string('accessdenied', 'error'),
'link' => '',
'selflink' => '',
'id' => '',
'description' => '',
'ownername' => '',
'updated' => '',
'logo' => '',
);
}
function error_post($message) {
return array(
0 => array(
'title' => get_string('accessdenied', 'error'),
'link' => '',
'id' => '',
'description' => $message,
'mtime' => '',
));
}
$artefactid = param_integer('artefact');
$viewid = param_integer('view');
require_once(get_config('docroot') . 'artefact/lib.php');
$artefact = artefact_instance_from_id($artefactid);
if (!can_view_view($viewid)) {
generate_feed(error_feed(), error_post(''));
}
elseif (!artefact_in_view($artefactid, $viewid)) {
generate_feed(error_feed(), error_post(get_string('artefactnotinview', 'error', $artefactid, $viewid)));
}
elseif (!$artefact->in_view_list()) {
generate_feed(error_feed(), error_post(get_string('artefactonlyviewableinview', 'error')));
}
elseif ($artefact->get('artefacttype') != 'blog') {
generate_feed(error_feed(), error_post(get_string('feedsnotavailable', 'artefact.blog')));
}
else {
$owner = get_records_sql_array("
SELECT a.mtime, u.id, u.firstname, u.lastname, u.profileicon
FROM {usr} u, {artefact} a
WHERE a.id = ?
AND a.owner = u.id
LIMIT 1;",
array($artefactid));
if ($owner[0]->profileicon) {
$image = get_config('wwwroot') . 'thumb.php?type=profileiconbyid&maxsize=100&id='
. $owner[0]->profileicon;
}
else {
// use the Mahara logo
$image = get_config('wwwroot') . 'theme/raw/static/images/site-logo.png';
}
// if the owner has a personal website set, use it as the author URI
$personal_site = get_field('artefact', 'title', 'artefacttype', 'personalwebsite', 'owner', $owner[0]->id);
$author = array(
'name' => implode(' ', array($owner[0]->firstname, $owner[0]->lastname)),
'uri' => $personal_site,
);
$link = get_config('wwwroot') . 'view/artefact.php?artefact=' .
$artefactid . '&view=' . $viewid;
$selflink = get_config('wwwroot') . 'artefact/blog/atom.php?artefact=' .
$artefactid . '&view=' . $viewid;
$postids = get_records_sql_array("
SELECT a.id, a.title, a.description, a.mtime
FROM {artefact} a, {artefact_blog_blogpost} bp
WHERE a.id = bp.blogpost
AND a.parent = ?
AND bp.published = 1
ORDER BY a.ctime DESC
LIMIT ?;",
array($artefactid, POSTCOUNT));
if ($postids) {
$updated = $postids[0]->mtime;
}
else {
$updated = $owner[0]->mtime;
}
$generator = array(
'uri' => 'http://mahara.org',
'version' => get_config('release'),
'text' => 'Mahara',
);
$rights = get_string('feedrights', 'artefact.blog', substr($updated, 0, 4) . ' ' . $author['name']);
// is there a Creative Commons block in this view?
// if so, set the feed rights accordingly
$ccblock = get_records_sql_array("
SELECT b.id
FROM {block_instance} b
WHERE b.view = ?
AND b.blocktype = 'creativecommons'
LIMIT 1;", array($viewid));
if ($ccblock) {
require_once(get_config('docroot') . 'blocktype/lib.php');
$ccblock_instance = new BlockInstance($ccblock[0]->id);
$configdata = $ccblock_instance->get('configdata');
$licensetype = $configdata['license'];
$licenseurl = "http://creativecommons.org/licenses/$licensetype/3.0/";
$licensename = get_string($licensetype, 'blocktype.creativecommons');
$rights .= ' ' . get_string('licensestatement', 'blocktype.creativecommons', $licenseurl, $licensename);
}
$feed = array(
'title' => $artefact->get('title'),
'link' => $link,
'selflink' => $selflink,
'id' => implode(',', array(get_config('wwwroot'), $artefactid, $viewid)),
'description' => $artefact->get('description'),
'author' => $author,
'updated' => atom_date($updated),
'logo' => $image,
'icon' => get_config('wwwroot') . 'favicon.ico',
'generator' => $generator,
'rights' => $rights,
);
$posts = array();
if ($postids) {
foreach ($postids as $postid) {
$post = artefact_instance_from_id($postid->id);
$attachments = $post->get_attachments();
$attachlinks = array();
foreach ($attachments as $attachment) {
$attachlinks[] = array(
'link' => get_config('wwwroot') . 'artefact/file/download.php?file=' .
$attachment->id . '&view=' . $viewid,
'title' => $attachment->title,
);
}
$posts[] = array(
'title' => $post->get('title'),
'link' => get_config('wwwroot') . 'view/artefact.php?artefact=' .
$post->get('id') . '&view=' . $viewid,
'id' => implode(',', array(get_config('wwwroot'), $post->get('id'), $viewid)),
'description' => $post->get('description'),
'mtime' => atom_date($postid->mtime),
'attachments' => $attachlinks,
);
}
}
generate_feed($feed, $posts);
}
...@@ -139,4 +139,7 @@ $string['postscopiedfromview'] = 'Posts copied from %s'; ...@@ -139,4 +139,7 @@ $string['postscopiedfromview'] = 'Posts copied from %s';
$string['youhavenoblogs'] = 'You have no blogs.'; $string['youhavenoblogs'] = 'You have no blogs.';
$string['youhaveoneblog'] = 'You have 1 blog.'; $string['youhaveoneblog'] = 'You have 1 blog.';
$string['youhaveblogs'] = 'You have %s blogs.'; $string['youhaveblogs'] = 'You have %s blogs.';
$string['feedsnotavailable'] = 'Feeds are not available for this artefact type.';
$string['feedrights'] = 'Copyright %s.';
?> ?>
<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>{$feed.title}</title>
<id>{$feed.id}</id>
<link href="{$feed.link|escape}" />
<link rel="self" type="application/atom+xml" href="{$feed.selflink|escape}" />
<subtitle type="html"><![CDATA[ {$feed.description} ]]></subtitle>
<logo>{$feed.logo|escape}</logo>
<icon>{$feed.icon|escape}</icon>
<generator uri="{$feed.generator.uri|escape}" version="{$feed.generator.version}">
{$feed.generator.text}
</generator>
<author>
<name>{$feed.author.name}</name>
{if $feed.author.uri}
<uri>{$feed.author.uri|escape}</uri>
{/if}
</author>
<updated>{$feed.updated}</updated>
<rights type="html"><![CDATA[ {$feed.rights} ]]></rights>
{foreach from=$posts item=post}
<entry>
<title>{$post.title}</title>
<id>{$post.id}</id>
<link href="{$post.link|escape}" />
<content type="html"><![CDATA[ {$post.description} ]]></content>
<author>
<name>{$feed.author.name}</name>
</author>
<updated>{$post.mtime}</updated>
<rights type="html"><![CDATA[ {$feed.rights} ]]></rights>
{foreach from=$post.attachments item=attachlink}
<link rel="enclosure" title="{$attachlink.title}" href="{$attachlink.link|escape}" />
{/foreach}
</entry>
{/foreach}
</feed>
...@@ -630,6 +630,13 @@ class BlockInstance { ...@@ -630,6 +630,13 @@ class BlockInstance {
. $configdata['artefactid'] . '&view=' . $this->get('view')); . $configdata['artefactid'] . '&view=' . $this->get('view'));
} }
// if the artefact has a feed and the view is public, display a feed icon
if ($this->get('blocktype') == 'blog' && $this->get('view_obj')->is_public()) {
$smarty->assign('hasfeed', true);
$smarty->assign('feedlink', get_config('wwwroot') . 'artefact/blog/atom.php?artefact='
. $configdata['artefactid'] . '&view=' . $this->get('view'));
}
$smarty->assign('content', $content); $smarty->assign('content', $content);
return $smarty->fetch('view/blocktypecontainerviewing.tpl'); return $smarty->fetch('view/blocktypecontainerviewing.tpl');
......
...@@ -96,6 +96,8 @@ $string['youcannotviewthisusersprofile'] = 'You cannot view this user\'s profile ...@@ -96,6 +96,8 @@ $string['youcannotviewthisusersprofile'] = 'You cannot view this user\'s profile
$string['artefactnotfoundmaybedeleted'] = "Artefact with id %s not found (maybe it has been deleted already?)"; $string['artefactnotfoundmaybedeleted'] = "Artefact with id %s not found (maybe it has been deleted already?)";
$string['artefactnotfound'] = 'Artefact with id %s not found'; $string['artefactnotfound'] = 'Artefact with id %s not found';
$string['artefactnotinview'] = 'Artefact %s not in View %s';
$string['artefactonlyviewableinview'] = 'Artefacts of this type are only viewable within a View';
$string['notartefactowner'] = 'You do not own this artefact'; $string['notartefactowner'] = 'You do not own this artefact';
$string['blockinstancednotfound'] = 'Block instance with id %s not found'; $string['blockinstancednotfound'] = 'Block instance with id %s not found';
......
...@@ -561,6 +561,21 @@ class View { ...@@ -561,6 +561,21 @@ class View {
return $data; return $data;
} }
public function is_public() {
$timeformat = get_string('strftimedatetimeshort');
$now = strtotime(date('Y/m/d H:i'));
foreach($this->get_access($timeformat) as $access) {
if($access['type'] == 'public' && (
($access['startdate'] == null && $access['stopdate'] == null) ||
($access['startdate'] == null && strtotime($access['stopdate']) > $now) ||
(strtotime($access['startdate']) < $now && $access['stopdate'] == null) ||
(strtotime($access['startdate']) < $now && strtotime($access['stopdate']) > $now))) {
return true;
}
}
return false;
}
public function set_access($accessdata) { public function set_access($accessdata) {
global $USER; global $USER;
require_once('activity.php'); require_once('activity.php');
......
...@@ -206,3 +206,8 @@ input.addcolumn, input.removecolumn { ...@@ -206,3 +206,8 @@ input.addcolumn, input.removecolumn {
background: none; background: none;
border: none; border: none;
} }
/* Feed icons */
img.feedicon {
margin-left: 10px;
}
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<h2> <h2>
<a href="{$WWWROOT}view/view.php?id={$viewid}">{$viewtitle|escape}</a>{if $ownername} {str tag=by section=view} <a href="{$WWWROOT}view/view.php?id={$viewid}">{$viewtitle|escape}</a>{if $ownername} {str tag=by section=view}
<a href="{$WWWROOT}{$ownerlink}">{$ownername|escape}</a>{/if}{foreach from=$artefactpath item=a}: <a href="{$WWWROOT}{$ownerlink}">{$ownername|escape}</a>{/if}{foreach from=$artefactpath item=a}:
{if $a.url}<a href="{$a.url}">{/if}{$a.title|escape}{if $a.url}</a>{/if} {if $a.url}<a href="{$a.url}">{/if}{$a.title|escape}{if $a.url}</a>{/if}{if $hasfeed}<a href="{$feedlink}"><img class="feedicon" src="{theme_url filename='images/rss.gif'}"></a>{/if}
{/foreach} {/foreach}
</h2> </h2>
......
<div class="blockinstance bt-{$blocktype|escape}" id="blockinstance_{$id}"> <div class="blockinstance bt-{$blocktype|escape}" id="blockinstance_{$id}">
{if $title}<div class="blockinstance-header"> {if $title}<div class="blockinstance-header">
<h4>{if $viewartefacturl}<a href="{$viewartefacturl|escape}" title="{str tag=clickformoreinformation section=view}">{/if}{$title|escape}{if $viewartefacturl}</a>{/if}</h4> <h4>{if $viewartefacturl}<a href="{$viewartefacturl|escape}" title="{str tag=clickformoreinformation section=view}">{/if}{$title|escape}{if $viewartefacturl}</a>{/if}{if $hasfeed}<a href="{$feedlink}"><img class="feedicon" src="{theme_url filename='images/rss.gif'}"></a>{/if}</h4>
</div>{/if} </div>{/if}
<div class="blockinstance-content"> <div class="blockinstance-content">
{$content} {$content}
......
...@@ -44,7 +44,7 @@ if (!can_view_view($viewid)) { ...@@ -44,7 +44,7 @@ if (!can_view_view($viewid)) {
} }
if (!artefact_in_view($artefactid, $viewid)) { if (!artefact_in_view($artefactid, $viewid)) {
throw new AccessDeniedException("Artefact $artefactid not in View $viewid"); throw new AccessDeniedException(get_string('artefactnotinview', 'error', $artefactid, $viewid));
} }
// Feedback list pagination requires limit/offset params // Feedback list pagination requires limit/offset params
...@@ -60,7 +60,7 @@ if (param_variable('make_private_submit', null)) { ...@@ -60,7 +60,7 @@ if (param_variable('make_private_submit', null)) {
} }
if (!$artefact->in_view_list()) { if (!$artefact->in_view_list()) {
throw new AccessDeniedException("Artefacts of this type are only viewable within a View"); throw new AccessDeniedException(get_string('artefactsonlyviewableinview', 'error'));
} }
define('TITLE', $artefact->display_title() . ' ' . get_string('in', 'view') . ' ' . $view->get('title')); define('TITLE', $artefact->display_title() . ' ' . get_string('in', 'view') . ' ' . $view->get('title'));
...@@ -114,9 +114,21 @@ $objectionform = pieform(objection_form()); ...@@ -114,9 +114,21 @@ $objectionform = pieform(objection_form());
$viewbeingwatched = (int)record_exists('usr_watchlist_view', 'usr', $USER->get('id'), 'view', $viewid); $viewbeingwatched = (int)record_exists('usr_watchlist_view', 'usr', $USER->get('id'), 'view', $viewid);
$headers = array('<link rel="stylesheet" type="text/css" href="' . get_config('wwwroot') . 'theme/views.css">',);
$hasfeed = false;
$feedlink = '';
// add a link to the ATOM feed in the header if the view is public
if($artefact->get('artefacttype') == 'blog' && $view->is_public()) {
$hasfeed = true;
$feedlink = get_config('wwwroot') . 'artefact/blog/atom.php?artefact=' .
$artefactid . '&view=' . $viewid;
$headers[] = '<link rel="alternate" type="application/atom+xml" href="' . $feedlink . '" />';
}
$smarty = smarty( $smarty = smarty(
array('paginator', 'feedbacklist'), array('paginator', 'feedbacklist'),
array('<link rel="stylesheet" type="text/css" href="' . get_config('wwwroot') . 'theme/views.css">'), $headers,
array(), array(),
array( array(
'stylesheets' => array('style/views.css'), 'stylesheets' => array('style/views.css'),
...@@ -132,6 +144,9 @@ $smarty->assign('viewid', $viewid); ...@@ -132,6 +144,9 @@ $smarty->assign('viewid', $viewid);
$smarty->assign('viewtitle', $view->get('title')); $smarty->assign('viewtitle', $view->get('title'));
$smarty->assign('feedback', $feedback); $smarty->assign('feedback', $feedback);
$smarty->assign('hasfeed', $hasfeed);
$smarty->assign('feedlink', $feedlink);
$viewowner = $view->get('owner'); $viewowner = $view->get('owner');
if ($viewowner) { if ($viewowner) {
$smarty->assign('ownerlink', 'user/view.php?id=' . $viewowner); $smarty->assign('ownerlink', 'user/view.php?id=' . $viewowner);
......
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