#!/usr/bin/php-cgi -dcgi.force_redirect=0
<?php
# encoding: utf-8
# api: cgi
# type: edit
# title: User editing
# description: Provides an editing interface to user fields (info)
# version: 0.2
# state: alpha
# depends: php:sqlite
# config: -
#
# Fairly simple editing UI for user.info table, and possibly some
# new fields. This is basically an addition to the IndieAuth plugin,
# so users can actually update their contact information etc.
#
# New fields must be added in $fields[] atop.
#
if ($_REQUEST["dbg"]) {
error_reporting(E_ALL); ini_set("display_errors", 1);
}
#-- allowed/new fields
$fields = [
"info" => [
"title" => "Contact info",
"desc" => "This is usually just an email address. For using git-fast-export this must be a single line.",
],
"homepage" => [
"title" => "Homepage URLs",
"desc" => "This will create a new column for listing user urls. Which is used by the IndieAuth plugin to verify authorization requests.",
],
];
#-- database (== fossil repo)
function db($sql="", $params=[]) {
static $db;
if (empty($db)) {
$db = new PDO("sqlite:$_SERVER[FOSSIL_REPOSITORY]");
}
if ($params) {
$stmt = $db->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
else {
return $db->query($sql);
}
}
#-- fossil HTML output
function page_html($html) {
header("Content-Type: text/html; encoding=utf-8");
$html = <<<HTML
<div class='fossil-doc' data-title='User config'>
<svg style="float:left; margin-right:30pt;" width="150" height="937" version="1.1" viewBox="0 0 15.635 93.735" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="linearGradient938" x1="48.584" x2="64.881" y1="88.509" y2="86.525" gradientUnits="userSpaceOnUse">
<stop stop-color="#5f9320" offset="0"/>
<stop stop-color="#bbb700" offset="1"/>
</linearGradient>
</defs>
<g transform="translate(-48.584 -41.642)">
<path d="m52.253 41.642c-2.0326 0-3.669 1.6359-3.669 3.6685v8.6589h2.8009c1.1504 0 2.0769 0.92645 2.0769 2.0769v1.8914a3.7084 3.675 0 0 1 3.5745-2.6985 3.7084 3.675 0 0 1 3.7083 3.6752 3.7084 3.675 0 0 1-3.7083 3.6747 3.7084 3.675 0 0 1-3.5745-2.713v2.2402c0 1.1504-0.92645 2.0764-2.0769 2.0764h-2.8009v13.23h2.9347c1.1504 0 2.0769 0.92645 2.0769 2.0769v1.8914a3.7084 3.675 0 0 1 3.5745-2.6985 3.7084 3.675 0 0 1 3.7083 3.6752 3.7084 3.675 0 0 1-3.7083 3.6747 3.7084 3.675 0 0 1-3.5745-2.713v2.2402c0 1.1504-0.92645 2.0764-2.0769 2.0764h-2.9347v11.61h2.9011c1.1504 0 2.0769 0.92644 2.0769 2.0769v1.8914a3.7084 3.675 0 0 1 3.5745-2.6985 3.7084 3.675 0 0 1 3.7083 3.6752 3.7084 3.675 0 0 1-3.7083 3.6747 3.7084 3.675 0 0 1-3.5745-2.713v2.2402c0 1.1504-0.92645 2.0764-2.0769 2.0764h-2.9011v13.23h3.035c1.1504 0 2.0769 0.92645 2.0769 2.0769v1.8914a3.7084 3.675 0 0 1 3.5745-2.6985 3.7084 3.675 0 0 1 3.7083 3.6752 3.7084 3.675 0 0 1-3.7083 3.6747 3.7084 3.675 0 0 1-3.5745-2.713v2.2402c0 1.1504-0.92645 2.0764-2.0769 2.0764h-2.8236c0.50205 1.4268 1.855 2.4458 3.4577 2.4458h8.2972c2.0326 0 3.669-1.6364 3.669-3.669v-10.269h-2.9011c-1.1504 0-2.0769-0.92594-2.0769-2.0764v-2.2402a3.7084 3.675 0 0 1-3.5745 2.713 3.7084 3.675 0 0 1-3.7083-3.6747 3.7084 3.675 0 0 1 3.7083-3.6752 3.7084 3.675 0 0 1 3.5745 2.6985v-1.8914c0-1.1504 0.92645-2.0769 2.0769-2.0769h2.9011v-12.328h-2.9011c-1.1504 0-2.0769-0.92594-2.0769-2.0764v-2.2402a3.7084 3.675 0 0 1-3.5745 2.713 3.7084 3.675 0 0 1-3.7083-3.6747 3.7084 3.675 0 0 1 3.7083-3.6752 3.7084 3.675 0 0 1 3.5745 2.6985v-1.8914c0-1.1504 0.92645-2.0769 2.0769-2.0769h2.9011v-12.511h-3.0014c-1.1504 0-2.0769-0.92594-2.0769-2.0764v-2.2402a3.7084 3.675 0 0 1-3.5745 2.713 3.7084 3.675 0 0 1-3.7083-3.6747 3.7084 3.675 0 0 1 3.7083-3.6752 3.7084 3.675 0 0 1 3.5745 2.6985v-1.8914c0-1.1504 0.92645-2.0769 2.0769-2.0769h3.0014v-12.328h-3.0014c-1.1504 0-2.0769-0.92594-2.0769-2.0764v-2.2402a3.7084 3.675 0 0 1-3.5745 2.713 3.7084 3.675 0 0 1-3.7083-3.6747 3.7084 3.675 0 0 1 3.7083-3.6752 3.7084 3.675 0 0 1 3.5745 2.6985v-1.8914c0-1.1504 0.92645-2.0769 2.0769-2.0769h2.451c-0.64562-1.0429-1.7969-1.7368-3.1187-1.7368z" fill="url(#linearGradient938)" stroke-width="0"/>
</g>
</svg>
\n$html\n
</div>
HTML;
print($html);
}
function missing_param($name) {
die(page_html("<h2>Missing input</h2><p>URL lacks <code>&$name=</code> parameter."));
}
function page_md($text) {
header("Content-Type: text/x-markdown; encoding=utf-8");
print($text);
}
function h($s) {
return htmlspecialchars($s, ENT_QUOTES|ENT_HTML5, "UTF-8");
}
#-- show available fields
function field_inputs($user, $names="info,homepage") {
global $fields;
// get existing columns
$values = db("SELECT $names FROM user WHERE login=?", [$user])[0];
// output form
$html = ""; $h = "h";
foreach ($fields as $name=>$props) {
extract($props);
$html .= <<<HTML
<p>
<h4>{$h($title ?: $name)}</h4>
<textarea name='{$h($name)}' rows=3 cols=80>{$h($values[$name])}</textarea>
<br>\n<small>{$desc}</small>
</p>\n
HTML;
}
return $html;
}
#-- store them back.
function save_fields($user) {
global $fields;
$allowed = array_keys($fields);
$existing_columns = array_keys(
db("SELECT * FROM user WHERE login=?", [$user])[0]
);
foreach ($fields as $name=>$value) {
if (!in_array($name, $allowed)) {
continue;
}
if (!in_array($name, $existing_columns)) {
db("
ALTER TABLE `user`
ADD `$name` TEXT DEFAULT ''
");
}
db("UPDATE user SET `$name`=? WHERE login=?", [$value, $user]);
}
page_html("User infos updated");
}
#-- run
$h = "h";
if (empty($user = $_SERVER["FOSSIL_USER"]) or in_array($user, ["anonymous", "nobody", "developer", "reader"])) {
page_html("<h2>Not logged in</h2><p>Edit contact infos requires an active <a href='../login'>login</a>.");
}
elseif (!empty($_POST["save"])) {
unset($_POST["save"]);
save_fields($user, $_POST);
}
else {
$html = field_inputs($user);
$html = <<<HTML
<h2>Edit user details</h2>
<form action="" method=POST>
{$html}
<p><input type=submit name=save value=Apply></p>
</form>
HTML;
page_html($html);
}
?>