Commit 4145878a authored by Robert Lyon's avatar Robert Lyon
Browse files

Bug 1790731: Allow custom url redirect



So a site can specify where a user ends up on normal login

Change-Id: Iab57bda8505fe7556e0692481502eeb409e93335
Signed-off-by: Robert Lyon's avatarRobert Lyon <robertl@catalyst.net.nz>
parent 91747fb7
<?php
/**
*
* @package mahara
* @subpackage admin
* @author Catalyst IT Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
* @copyright For copyright information on Mahara, please see the README file distributed with this software.
*
*/
define('INTERNAL', 1);
define('ADMIN', 1);
define('JSON', 1);
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
global $USER;
$request = param_variable('q');
$page = param_integer('page');
if ($page < 1) {
$page = 1;
}
$resultsperpage = 10;
$more = true;
$tmpresults = array();
while ($more && count($tmpresults) < $resultsperpage) {
$results = get_homepage_redirect_results($request, $resultsperpage, $resultsperpage * ($page - 1));
$more = $results['count'] > $resultsperpage * $page;
if (!$results['data']) {
$results['data'] = array();
}
foreach ($results['data'] as $result) {
if (count($tmpresults) >= $resultsperpage) {
$more = true;
continue;
}
$title = $result->title;
if ($result->institution && empty($result->group)) {
if ($result->institution == 'mahara') {
$title .= ' (' . get_string('Site') . ')';
}
else {
$title .= ' (' . get_field('institution', 'displayname', 'name', $result->institution) . ')';
}
}
else if ($result->group) {
$title .= ' (' . get_field('group', 'name', 'id', $result->group) . ')';
}
else if ($result->owner) {
$title .= ' (' . display_name($result->owner, null, true) . ')';
}
$tmpresults[] = (object) array('id' => $result->url,
'text' => $title);
}
$page++;
}
echo json_encode(array(
'more' => $more,
'results' => $tmpresults,
));
......@@ -104,6 +104,27 @@ $siteoptionform = array(
'defaultvalue' => get_config('homepageinfo'),
'disabled' => in_array('homepageinfo', $OVERRIDDEN),
),
'homepageredirect' => array(
'type' => 'switchbox',
'title' => get_string('homepageredirect', 'admin'),
'description' => get_string('homepageredirectdescription', 'admin'),
'defaultvalue' => get_config('homepageredirect'),
'disabled' => in_array('homepageredirect', $OVERRIDDEN),
),
'homepageredirecturl' => array(
'type' => 'autocomplete',
'title' => get_string('homepageredirecturl', 'admin'),
'ajaxurl' => get_config('wwwroot') . 'admin/site/homepageredirect.json.php',
'multiple' => true,
'initfunction' => 'translate_landingpage_to_tags',
'ajaxextraparams' => array(),
'extraparams' => array(
'maximumSelectionLength' => 1
),
'description' => get_string('homepageredirecturldescription', 'admin'),
'defaultvalue' => get_config('homepageredirecturl'),
'disabled' => in_array('homepageredirect', $OVERRIDDEN),
),
),
),
'usersettings' => array(
......@@ -824,7 +845,7 @@ function siteoptions_submit(Pieform $form, $values) {
'defaultaccountlifetime', 'defaultregistrationexpirylifetime', 'defaultaccountinactiveexpire', 'defaultaccountinactivewarn',
'defaultaccountlifetimeupdate', 'allowpublicviews', 'allowpublicprofiles', 'allowanonymouspages', 'generatesitemap',
'mathjax', 'institutionexpirynotification', 'institutionautosuspend', 'requireregistrationconfirm',
'institutionstrictprivacy',
'institutionstrictprivacy', 'homepageredirect', 'homepageredirecturl',
'showselfsearchsideblock', 'nousernames', 'searchplugin', 'showtagssideblock',
'tagssideblockmaxtags', 'country', 'timezone', 'userscanchooseviewthemes', 'internalnotificationexpire',
'remoteavatars', 'userscanhiderealnames', 'antispam', 'spamhaus', 'surbl', 'anonymouscomments', 'passwordpolicy',
......@@ -911,7 +932,8 @@ function siteoptions_submit(Pieform $form, $values) {
", array($USER->get('id'))); // Ignore the root and current admin user
db_commit();
}
// Turn homepageredirecturl into string
$values['homepageredirecturl'] = !empty($values['homepageredirecturl']) ? $values['homepageredirecturl'][0] : '';
$oldsearchplugin = get_config('searchplugin');
$oldlanguage = get_config('lang');
$oldtheme = get_config('theme');
......@@ -1053,8 +1075,12 @@ jQuery(function() {
jQuery('#siteoptions_usersallowedmultipleinstitutions').on("click", function() {
strictprivacycheckallowed();
});
jQuery('#siteoptions_homepageredirect').on("click", function() {
homepageredirect();
});
multipleinstitutionscheckallowed();
strictprivacycheckallowed();
homepageredirect();
});
......
......@@ -1836,6 +1836,13 @@ function login_submit(Pieform $form, $values) {
$scriptname = $_SERVER['SCRIPT_NAME'];
$scriptname = str_replace($path, '', $scriptname);
$requesturi = $scriptname . (!empty($_SERVER['QUERY_STRING']) ? '?' . $_SERVER['QUERY_STRING'] : '');
if ($requesturi == '/' || $requesturi == '/index.php') {
// we are going to the homepage
if (get_config('homepageredirect') && !empty(get_config('homepageredirecturl'))) {
$requesturi = get_config('homepageredirecturl');
}
}
redirect($requesturi);
}
......
......@@ -190,6 +190,10 @@ if ($can_login) {
if (!preg_match('/'.$_SERVER['HTTP_HOST'] . '/', $wantsurl)) {
$wantsurl = $CFG->wwwroot;
}
// if redirecting to using homepage but using custom landing page
if ($wantsurl === $CFG->wwwroot && get_config('homepageredirect') && !empty(get_config('homepageredirecturl'))) {
$wantsurl = get_config('homepageredirecturl');
}
@session_write_close();
redirect($wantsurl);
}
......
......@@ -530,6 +530,19 @@ function editgroup_submit(Pieform $form, $values) {
'feedbacknotify' => intval($values['feedbacknotify']),
);
// Check to see if the group's forum is being used as a landing page url and if the changes affect it
if ($group_data->id && get_config('homepageredirect') && !empty(get_config('homepageredirecturl'))) {
$landing = translate_landingpage_to_tags(array(get_config('homepageredirecturl')));
foreach ($landing as $land) {
$forumgroup = get_field('interaction_instance', 'group', 'id', $land->typeid);
if ($land->type == 'forum' && !empty($forumgroup) && $forumgroup == $group_data->id && empty($newvalues['public'])) {
set_config('homepageredirecturl', null);
notify_landing_removed($land);
$SESSION->add_error_msg(get_string('landingpagegone', 'admin', $land->text));
}
}
}
// Only admins can only update shortname.
if (isset($values['shortname']) && $USER->can_edit_group_shortname($group_data)) {
$newvalues['shortname'] = $values['shortname'];
......
......@@ -30,6 +30,17 @@ if ($membership != 'admin') {
define('TITLE', get_string('deleteinteraction', 'group', get_string('name', 'interaction.' . $instance->get('plugin')), $instance->get('title')));
// submit handler in interaction/lib.php
// Check to see if the forum is being used as a landing page url
$landingpagenote = '';
if (get_config('homepageredirect') && !empty(get_config('homepageredirecturl'))) {
$landing = translate_landingpage_to_tags(array(get_config('homepageredirecturl')));
foreach ($landing as $land) {
if ($land->type == 'forum' && $land->typeid == $id) {
$landingpagenote = get_string('islandingpage', 'admin');
}
}
}
$returnto = param_alpha('returnto', 'view');
$form = pieform(array(
......@@ -54,5 +65,6 @@ $smarty = smarty(array('tablerenderer'));
$smarty->assign('form', $form);
$smarty->assign('heading', $group->name);
$smarty->assign('subheading', TITLE);
$smarty->assign('landingpagenote', $landingpagenote);
$smarty->assign('message', get_string('deleteinteractionsure', 'group'));
$smarty->display('interaction/delete.tpl');
......@@ -830,6 +830,16 @@ class InteractionForumInstance extends InteractionInstance {
}
db_begin();
// Check to see if the group's forum is being used as a landing page url and if the changes affect it
if (get_config('homepageredirect') && !empty(get_config('homepageredirecturl'))) {
$landing = translate_landingpage_to_tags(array(get_config('homepageredirecturl')));
foreach ($landing as $land) {
if ($land->type == 'forum' && $land->typeid == $this->id) {
set_config('homepageredirecturl', null);
notify_landing_removed($land, true);
}
}
}
// Delete embedded images in the forum description
require_once('embeddedimage.php');
EmbeddedImage::delete_embedded_images('forum', $this->id);
......
......@@ -41,6 +41,19 @@ function strictprivacycheckallowed() {
}
}
// we need to toggle the homepageredirecturl field depending on state of homepageredirect
function homepageredirect() {
var target = jQuery('#siteoptions_homepageredirecturl');
if (jQuery('#siteoptions_homepageredirect').is(':checked')) {
target.parent().removeClass('hidden');
target.prop('disabled', false);
}
else {
target.parent().addClass('hidden');
target.prop('disabled', true);
}
}
var checkReload = (function($) {
// Disconnects the pieform submit handler and changes the form target back to
// the page itself (rather than pieform's hidden iframe), so a full post/reload
......@@ -90,8 +103,12 @@ var checkReload = (function($) {
jQuery('#siteoptions_usersallowedmultipleinstitutions').on("click", function() {
strictprivacycheckallowed();
});
jQuery('#siteoptions_homepageredirect').on("click", function() {
homepageredirect();
});
multipleinstitutionscheckallowed();
strictprivacycheckallowed();
homepageredirect();
formSuccess(form, data);
};
......
......@@ -392,6 +392,15 @@ $string['generatesitemap1'] = 'Sitemap';
$string['generatesitemapdescription'] = 'Generate sitemap files from publicly accessible pages, groups and forum topics';
$string['homepageinfo1'] = 'Show homepage / dashboard information';
$string['homepageinfodescription3'] = 'Show information about Mahara and how it is used on the Mahara homepage. Registered users will have the option to disable it for their dashboard.';
$string['homepageredirect'] = 'Custom landing page';
$string['homepageredirectdescription'] = 'If you want the first page a user sees after logging in to be something other than the dashboard page. Note: If a link was clicked that requires the user to log in, that redirect will take priority.';
$string['homepageredirecturl'] = 'Landing page';
$string['homepageredirecturldescription'] = 'For this to work, the page needs to be accessible to all registered users.';
$string['islandingpage'] = 'This page is used as custom landing page for the site.';
$string['landingpagegone'] = 'The page "%s" was the custom landing page for the site before you made the permission change. It has been removed as the custom landing page from the site settings.';
$string['landingpagegonesubject'] = 'Custom landing page removed';
$string['landingpagegonemessage'] = 'Please log in and choose a new custom landing page in the site settings.';
$string['landingpagegonemessagedeleted'] = 'The page "%s" was removed as the custom landing page for the site because the page was deleted. Please log in and choose a new custom landing page in the site settings.';
$string['institutionautosuspend'] = 'Auto-suspend expired institutions';
$string['institutionautosuspenddescription1'] = 'Automatically suspend expired institutions.';
$string['institutionexpirynotification'] = 'Warning time for institution expiry';
......
......@@ -5478,3 +5478,145 @@ function get_password_policy_description($type = 'generic') {
}
return $description;
}
function get_homepage_redirect_results($request, $limit, $offset, $type = null, $id = null) {
$admins = get_site_admins();
$adminids = array();
foreach ($admins as $admin) {
$adminids[] = $admin->id;
}
$results = array('count' => 0,
'data' => array());
if ($type) {
$results['count'] = 1;
$results['data'][] = get_record($type, 'id', $id);
}
else {
$countsql = "SELECT COUNT(*) FROM (";
$resultsql = "SELECT * FROM (";
$fromsql = "SELECT v.id, v.title, v.owner, v.group, v.institution, 'view' AS urltype
FROM {view} v
JOIN {view_access} va ON va.view = v.id
LEFT JOIN {group} g ON g.id = v.group
LEFT JOIN {institution} i ON i.name = v.institution
WHERE va.accesstype IN ('public', 'loggedin')
AND v.type != 'profile'
AND (
(v.owner IS NULL AND v.template != 2)
OR
(v.owner IN (" . join(',', array_map('db_quote', $adminids)) . "))
)
AND (v.title ILIKE ? OR g.name ILIKE ? OR i.name ILIKE ?)
UNION
SELECT ii.id, ii.title, NULL AS owner, g.id AS group, g.institution, 'forum' AS urltype
FROM {interaction_instance} ii
JOIN {group} g ON g.id = ii.group
WHERE g.public = 1
AND ii.deleted = 0
AND (ii.title ILIKE ?)
) AS foo OFFSET ? LIMIT ?";
$where = array('%' . $request . '%',
'%' . $request . '%',
'%' . $request . '%',
'%' . $request . '%',
$offset, $limit);
if ($count = count_records_sql($countsql . $fromsql, $where)) {
$results['count'] = $count;
$results['data'] = get_records_sql_array($resultsql . $fromsql, $where);
foreach ($results['data'] as $key => $value) {
if ($value->urltype == 'view') {
$value->url = '/view/view.php?id=' . $value->id;
}
if ($value->urltype == 'forum') {
$value->url = '/interaction/forum/view.php?id=' . $value->id;
}
}
}
}
return $results;
}
function translate_landingpage_to_tags(array $ids) {
$ids = array_diff($ids, array(''));
$results = array();
if (!empty($ids)) {
foreach ($ids as $id) {
if (preg_match('/forum\/view\.php\?id=(\d+)/', $id, $matches)) {
$data = get_homepage_redirect_results(null, null, null, 'interaction_instance', $matches[1]);
$type = 'forum';
$typeid = $matches[1];
$result = $data['data'][0];
$text = $result->title . ' (' . get_field('group', 'name', 'id', $result->group) . ')';
}
else if (preg_match('/view\.php\?id=(\d+)/', $id, $matches)) {
$data = get_homepage_redirect_results(null, null, null, 'view', $matches[1]);
$type = 'view';
$typeid = $matches[1];
$result = $data['data'][0];
$text = $result->title;
if ($result->institution) {
if ($result->institution == 'mahara') {
$text .= ' (' . get_string('Site') . ')';
}
else {
$text .= ' (' . get_field('institution', 'displayname', 'name', $result->institution) . ')';
}
}
else if ($result->group) {
$text .= ' (' . get_field('group', 'name', 'id', $result->group) . ')';
}
else if ($result->owner) {
$text .= ' (' . display_name($result->owner, null, true) . ')';
}
}
else {
$text = $typeid = $id;
$type = 'unknown';
}
$results[] = (object) array('id' => $id, 'text' => $text, 'type' => $type, 'typeid' => $typeid);
}
}
return $results;
}
function notify_landing_removed($landingpage, $deleted=false) {
require_once('activity.php');
$admins = array();
foreach (get_site_admins() as $site_admin) {
$admins[] = $site_admin->id;
}
if ($landingpage->type == 'forum') {
$forumgroup = get_field('interaction_instance', 'group', 'id', $landingpage->typeid);
$admins = array_merge($admins, group_get_admin_ids($forumgroup));
}
$admins = array_unique($admins);
$message = $deleted ? 'landingpagegonemessagedeleted' : 'landingpagegonemessage';
$messageargs = $deleted ? array($landingpage->text) : array();
if ($deleted) {
$url = get_config('wwwroot') . 'admin/site/options.php';
}
else {
$url = preg_replace('/^\//', '', $landingpage->id);
}
activity_occurred('maharamessage', array(
'users' => $admins,
'subject' => '',
'message' => '',
'strings' => (object) array(
'subject' => (object) array(
'key' => 'landingpagegonesubject',
'section' => 'admin',
'args' => array(),
),
'message' => (object) array(
'key' => $message,
'section' => 'admin',
'args' => $messageargs,
),
),
'url' => $url,
));
}
......@@ -1000,6 +1000,17 @@ class View {
$bi->delete();
}
}
// Check if this view is being used as the custom landing page
if (get_config('homepageredirect') && !empty(get_config('homepageredirecturl'))) {
$landing = translate_landingpage_to_tags(array(get_config('homepageredirecturl')));
foreach ($landing as $land) {
if ($land->type == 'view' && $land->typeid == $this->id) {
set_config('homepageredirecturl', null);
notify_landing_removed($land, true);
}
}
}
handle_event('deleteview', $eventdata);
delete_records('view_rows_columns', 'view', $this->id);
delete_records('view','id',$this->id);
......@@ -1112,6 +1123,7 @@ class View {
}
public static function update_view_access($config, $viewids) {
global $SESSION;
db_begin();
......@@ -1123,6 +1135,26 @@ class View {
// Copy the first view's access records to all the other views
$firstview->copy_access($viewids);
// Check to see if the view is being used as a landing page url and if the access changes affect it
if (get_config('homepageredirect') && !empty(get_config('homepageredirecturl'))) {
$landing = translate_landingpage_to_tags(array(get_config('homepageredirecturl')));
foreach ($landing as $land) {
if ($land->type == 'view' && in_array($land->typeid, $viewids)) {
$landingproblem = true;
foreach ($config['accesslist'] as $access) {
if (in_array($access['type'], array('loggedin', 'public'))) {
$landingproblem = false;
}
}
if ($landingproblem) {
set_config('homepageredirecturl', null);
notify_landing_removed($land);
$SESSION->add_error_msg(get_string('landingpagegone', 'admin', $land->text));
}
}
}
}
// Sort the full access list in the same order as the list
// returned by get_access, so that views with the same set of
// access records get grouped together
......
......@@ -422,7 +422,7 @@ EOD;
'invitefriends' => isset($record['invitefriends']) ? $record['invitefriends'] : 0,
'suggestfriends' => isset($record['suggestfriends']) ? $record['suggestfriends'] : 0,
'category' => null,
'public' => 0,
'public' => isset($record['public']) ? $record['public'] : 0,
'usersautoadded' => 0,
'viewnotify' => GROUP_ROLES_ALL,
'submittableto' => isset($record['submittableto']) ? $record['submittableto'] : 0,
......
......@@ -75,6 +75,7 @@ class BehatDataGenerators extends BehatBase {
'staff' => 'text',
'admins' => 'text',
'institution' => 'text',
'public' => 'bool',
),
'required' => array('name', 'owner'),
),
......
......@@ -2,6 +2,7 @@
<div class="panel panel-danger view-container">
<h2 class="panel-heading">{$subheading}</h2>
<div class="panel-body">
{if $landingpagenote}<p class="lead">{$landingpagenote}</p>{/if}
<p>{$message}</p>
{$form|safe}
</div>
......
......@@ -5,7 +5,8 @@
{str tag="deleteviewconfirm1" section="view"}
</h2>
<div class="panel-body">
<p class="lead">{if $collectionnote}{$collectionnote|clean_html|safe}{/if}</p>
{if $collectionnote}<p class="lead">{$collectionnote|clean_html|safe}</p>{/if}
{if $landingpagenote}<p class="lead">{$landingpagenote}</p>{/if}
<p>{if $view->get('owner')}
{str tag="deleteviewconfirmbackup" section="view" arg1=$WWWROOT}
{/if}</p>
......
......@@ -30,6 +30,17 @@ if ($collection) {
$collectionnote = get_string('deleteviewconfirmnote2', 'view', $collection->get_url(), $collection->get('name'));
}
// Check to see if the view is being used as a landing page url
$landingpagenote = '';
if (get_config('homepageredirect') && !empty(get_config('homepageredirecturl'))) {
$landing = translate_landingpage_to_tags(array(get_config('homepageredirecturl')));
foreach ($landing as $land) {
if ($land->type == 'view' && $land->typeid == $viewid) {
$landingpagenote = get_string('islandingpage', 'admin');
}
}
}
$institution = $view->get('institution');
View::set_nav($groupid, $institution);
......@@ -101,6 +112,7 @@ $smarty = smarty();
$smarty->assign('view', $view);
$smarty->assign('form', $form);
$smarty->assign('collectionnote', $collectionnote);
$smarty->assign('landingpagenote', $landingpagenote);
$smarty->display('view/delete.tpl');
function deleteview_submit(Pieform $form, $values) {
......
@javascript @core @core_account @core_login
Feature: Setting a custom landing page on login
In order to show a page other than dashboard on login
As an admin
I can set the custom landing page
As a user
I can see custom page on login
Background:
Given the following "users" exist:
| username | password | email | firstname | lastname | institution | authname | role |
| UserA | Kupuh1pa! | UserA@example.org | Angela | User | mahara | internal | member |
And the following "groups" exist:
| name | owner | description | grouptype | open | invitefriends | editroles | submittableto | allowarchives | members | public |
| GroupX | admin | GroupX owned by admin | standard | ON | ON | all | ON | ON | UserA | 1 |
And the following "pages" exist:
| title | description | ownertype | ownername |
| Page admin_01 | This is the landing page | user | admin |
And the following "permissions" exist:
| title | accesstype | accessname | allowcomments | approvecomments |
| Page admin_01 | loggedin | loggedin | 0 | 0 |
Scenario: Set the custom landing page
Given I log in as "admin" with password "Kupuh1pa!"
And I choose "Configure site" from administration menu
# I set the custom landing option
And I expand the section "Site settings"
And I enable the switch "Custom landing page"
# Check if we can use forum topic as landing page
When I fill in select2 input "siteoptions_homepageredirecturl" with "General" and select "General discussion (GroupX)"
And I press "Update site options"
And I log out
# Now see if we land on forum page
Given I log in as "UserA" with password "Kupuh1pa!"
Then I should see "GroupX general discussion forum"
And I log out
Given I log in as "admin" with password "Kupuh1pa!"
And I choose "Configure site" from administration menu
# I set the custom landing option
And I expand the section "Site settings"
# Check if we can use a page as landing page
And I clear value "General discussion (GroupX)" from select2 field "siteoptions_homepageredirecturl"
When I fill in select2 input "siteoptions_homepageredirecturl" with "Page admin_01" and select "Page admin_01 (Admin User)"
And I press "Update site options"
And I log out
# Now see if we land on user page
Given I log in as "UserA" with password "Kupuh1pa!"
Then I should see "This is the landing page"
And I log out
Given I log in as "admin" with password "Kupuh1pa!"
And I choose "Configure site" from administration menu
# I set the custom landing option
And I expand the section "Site settings"
And I disable the switch "Custom landing page"