summaryrefslogtreecommitdiff
path: root/example
diff options
context:
space:
mode:
authordefanor <defanor@uberspace.net>2018-12-30 13:05:36 +0300
committerdefanor <defanor@uberspace.net>2018-12-30 13:05:36 +0300
commit1b3ea5d48e049c595f90eb8b9fb11f8149927519 (patch)
tree979b85238d5f40f05284993c40b98428ca63a8a8 /example
Initial commit
The initial working version, an example, and brief description are included. Error handling and reporting, perhaps HTTP headers, CLI arguments, and documentation can still be improved, but that's for future commits.
Diffstat (limited to 'example')
-rw-r--r--example/README.md18
-rw-r--r--example/bugs.sql37
-rw-r--r--example/common.xsl40
-rw-r--r--example/list.xsl92
-rw-r--r--example/view.xsl26
5 files changed, 213 insertions, 0 deletions
diff --git a/example/README.md b/example/README.md
new file mode 100644
index 0000000..b6cfbfa
--- /dev/null
+++ b/example/README.md
@@ -0,0 +1,18 @@
+# pg×html usage example
+
+Here is an example that implements a very basic bug reporting system:
+users can just report, view, and list (search) the bugs.
+
+First of all, a database should be designed: `bugs.sql` contains
+definitions and comments.
+
+A common template, `common.xsl`, includes error handling and some
+shared HTML. One can choose to show error details to users, or to hide
+them.
+
+`view.xsl` is a basic template for bug viewing.
+
+`list.xsl` includes report and search forms, and lists the bugs.
+
+To quickly try it, run `pgxhtml --devlogging` in this directory,
+with database connection environment variables set if needed.
diff --git a/example/bugs.sql b/example/bugs.sql
new file mode 100644
index 0000000..033a1f7
--- /dev/null
+++ b/example/bugs.sql
@@ -0,0 +1,37 @@
+-- pgcrypto is needed for UUIDs.
+create extension pgcrypto;
+
+-- A table with defaults and constraints.
+create table bugs (
+ id uuid not null primary key default gen_random_uuid(),
+ reported timestamp with time zone not null default now(),
+ reporter varchar not null default current_user,
+ project varchar(256) not null check (project <> ''),
+ description varchar(10240) not null check (description <> '')
+);
+
+-- No indexes, since they are irrelevant to this example (but normally
+-- they should be there).
+
+-- Additional restrictions.
+create policy bugs_select_policy on bugs for select using (true);
+create policy bugs_insert_policy on bugs for insert
+ with check (reported = now() and reporter = current_user);
+-- Update and delete policies can be added later.
+alter table bugs enable row level security;
+
+-- A search function for convenience.
+create or replace function bug_search (proj varchar, descr varchar, lim int, offs int)
+returns xml
+as $$
+ select query_to_xml(
+ 'select id, date_trunc(''second'', reported) as reported, reporter, '
+ || 'project, substring(description from ''[^\n\r]+'') as summary from bugs '
+ || 'where (project like ' || quote_literal('%' || proj || '%')
+ || ') and (description like ' || quote_literal('%' || descr || '%')
+ || ') order by reported desc limit ' || lim || ' offset ' || offs,
+ false, false, 'bugs')
+$$ language sql;
+
+-- Now users can be added with select and/or insert privileges,
+-- including a guest user for unauthenticated requests.
diff --git a/example/common.xsl b/example/common.xsl
new file mode 100644
index 0000000..1db0229
--- /dev/null
+++ b/example/common.xsl
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.w3.org/1999/xhtml"
+ version="1.0">
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/">
+ <html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>Bugs</title>
+ </head>
+ <body>
+ <xsl:apply-templates select="*" />
+ </body>
+ </html>
+ </xsl:template>
+
+ <xsl:template match="sql_error">
+ <h1>SQL error</h1>
+ <dl>
+ <dt>State</dt>
+ <dd><xsl:copy-of select="@state/text()" /></dd>
+ <dt>Status</dt>
+ <dd><xsl:copy-of select="@status/text()" /></dd>
+ <dt>Message</dt>
+ <dd><xsl:copy-of select="@message/text()" /></dd>
+ <dt>Detail</dt>
+ <dd><xsl:copy-of select="@detail/text()" /></dd>
+ <dt>Hint</dt>
+ <dd><xsl:copy-of select="@hint/text()" /></dd>
+ <dt>Query template</dt>
+ <dd><xsl:copy-of select="@template/text()" /></dd>
+ <dt>Query parameters</dt>
+ <dd><xsl:copy-of select="@parameters/text()" /></dd>
+ </dl>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/example/list.xsl b/example/list.xsl
new file mode 100644
index 0000000..86c3150
--- /dev/null
+++ b/example/list.xsl
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.w3.org/1999/xhtml"
+ version="1.0">
+ <xsl:output method="xml" indent="yes"/>
+ <xsl:include href="common.xsl"/>
+ <xsl:param name="project" />
+ <xsl:param name="description" />
+ <xsl:param name="limit" select="10" />
+ <xsl:param name="offset" select="0" />
+
+ <xsl:template match="table">
+ <!-- Report form -->
+ <h2>Report</h2>
+ <form method="post" action="view.xhtml?q=insert%20into%20bugs%20(%20:fields%20)%20values%20(%20:values%20)%20returning%20xmlelement(name%20table,xmlelement(name%20row,xmlelement(name%20id,id),xmlelement(name%20reported,reported),xmlelement(name%20reporter,reporter),xmlelement(name%20project,project),xmlelement(name%20description,description)))">
+ <dl>
+ <dt><label for="report_project">Project</label></dt>
+ <dd>
+ <input type="text" name="project" id="report_project"
+ required="required" maxlength="128"
+ placeholder="Project name or URL" />
+ </dd>
+ <dt><label for="report_description">Description</label></dt>
+ <dd>
+ <textarea name="description" required="required"
+ id="report_description" maxlength="10240"
+ placeholder="Issue description" />
+ </dd>
+ </dl>
+ <input type="submit" value="Report" />
+ </form>
+
+ <!-- Search form -->
+ <h2>Search</h2>
+ <form method="get" action="list.xhtml">
+ <dl>
+ <dt><label for="search_project">Project</label></dt>
+ <dd>
+ <input id="search_project" type="search" name="project"
+ value="{$project}" />
+ </dd>
+ <dt><label for="search_description">Description</label></dt>
+ <dd>
+ <input id="search_description" type="search" name="description"
+ value="{$description}" />
+ </dd>
+ <dt><label for="search_limit">Limit</label></dt>
+ <dd>
+ <input id="search_limit" type="number" name="limit" min="1"
+ value="{$limit}" />
+ </dd>
+ <dt><label for="search_offset">Offset</label></dt>
+ <dd>
+ <input id="search_offset" type="number" name="offset" min="0"
+ value="{$offset}" />
+ </dd>
+ <input type="hidden" name="q"
+ value="select bug_search( q:project , q:description , q:limit , q:offset )" />
+ </dl>
+ <input type="submit" value="Search" />
+ </form>
+
+ <!-- Search results -->
+ <table>
+ <tr>
+ <th>Reported</th>
+ <th>Reporter</th>
+ <th>Project</th>
+ <th>Summary</th>
+ </tr>
+ <xsl:for-each select="row">
+ <tr>
+ <td><xsl:copy-of select="reported/text()" /></td>
+ <td><xsl:copy-of select="reporter/text()" /></td>
+ <td>
+ <a href="list.xhtml?q=select%20bug_search('{project/text()}','',{$limit},{$offset})">
+ <xsl:copy-of select="project/text()" />
+ </a>
+ </td>
+ <td>
+ <a href="view.xhtml?q=select%20query_to_xml('select%20*%20from%20bugs%20where%20id=''{id}''',false,false,'foo')">
+ <xsl:copy-of select="summary/text()" />
+ </a>
+ </td>
+ </tr>
+ </xsl:for-each>
+ </table>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/example/view.xsl b/example/view.xsl
new file mode 100644
index 0000000..af0e090
--- /dev/null
+++ b/example/view.xsl
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.w3.org/1999/xhtml"
+ version="1.0">
+ <xsl:output method="xml" indent="yes"/>
+ <xsl:include href="common.xsl"/>
+
+ <xsl:template match="table/row">
+ <a href="list.xhtml?q=select%20bug_search(%27%27,%20%27%27,%2010,%200)">back to listing</a>
+ <dl>
+ <dt>ID</dt>
+ <dd><xsl:copy-of select="id/text()" /></dd>
+ <dt>Reported</dt>
+ <dd><xsl:copy-of select="reported/text()" /></dd>
+ <dt>Reporter</dt>
+ <dd><xsl:copy-of select="reporter/text()" /></dd>
+ <dt>Project</dt>
+ <dd><xsl:copy-of select="project/text()" /></dd>
+ <dt>Description</dt>
+ <dd><pre><xsl:copy-of select="description/text()" /></pre></dd>
+ </dl>
+ </xsl:template>
+
+</xsl:stylesheet>