Browse Source

initial commit of current wip

master
René Wagner 7 months ago
commit
e3616bfde0
  1. 2
      .gitignore
  2. 29
      LICENSE
  3. 17
      README.md
  4. BIN
      data/data.sqlite.example
  5. 2
      gmnifaq.conf.example
  6. 97
      index.pl
  7. 105
      tags.pl

2
.gitignore

@ -0,0 +1,2 @@
data/data.sqlite
gmnifaq.conf

29
LICENSE

@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2018-2020, René Wagner
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

17
README.md

@ -0,0 +1,17 @@
# gmnifaq
gmnifaq is going to be a simple, self-hostable FAQ-engine for the [gemini protocol](gemini://gemini.circumlunar.space)
## planned features
- support for tags
- searching
- view by tag
- view all
## requirements
- gemini server with cgi enabled
- Perl >= 5.28
- SQLite

BIN
data/data.sqlite.example

2
gmnifaq.conf.example

@ -0,0 +1,2 @@
$sitename = 'gemini faq';
$siteintro = 'Welcome to gmnifaq, the simple cgi engine for your gemini capsule';

97
index.pl

@ -0,0 +1,97 @@
#!/usr/bin/perl
# Copyright René Wagner 2020
# licenced under BSD 3-Clause licence
# https://git.sr.ht/~rwa/gmni-perl-cgi-demo
use strict;
use DBI;
# define return codes
our %RC = (
'INPUT', 10,
'SENSITIVE_INPUT', 11,
'SUCCESS', 20,
'TEMPORARY_REDIRECT', 30,
'PERMANENT_REDIRECT', 31,
'TEMPORARY_FAILURE', 40,
'SERVER_UNAVAILABLE', 41,
'CGI_ERROR', 42,
'PROXY_ERROR', 43,
'SLOW_DOWN', 44,
'PERMANENT_FAILURE', 50,
'NOT_FOUND', 51,
'GONE', 52,
'PROXY_REQUEST_REFUSE', 53,
'BAD_REQUEST', 59,
'CLIENT_CERT_REQUIRED', 60,
'CERT_NOT_AUTHORISED', 61,
'CERT_NOT_VALID', 62
);
my $sitename = 'gmnifaq';
my $siteintro = 'Welcome to gmnifaq!';
my $dsn = "DBI:SQLite:dbname=data/data.sqlite";
# enable UTF-8 mode for everything
use utf8;
binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';
if (!defined($ENV{'SERVER_PROTOCOL'}) || $ENV{'SERVER_PROTOCOL'} ne 'GEMINI')
{
write_response('CGI_ERROR', 'CGI execution error', undef);
}
if ( -f './gmnifaq.conf' ) { do './gmnifaq.conf'; }
if ( !-f 'data/data.sqlite' ) { write_response('PERMANENT_FAILURE', 'Permanent failure', undef) };
my @body = ();
push @body, '# Welcome to '. $sitename;
push @body, '';
push @body, $siteintro;
push @body, '';
push @body, header();
push @body, '';
push @body, '## Meta';
push @body, '';
push @body, 'Search';
push @body, '=> tags.pl Tags';
push @body, 'View all';
push @body, footer();
write_response('SUCCESS', 'text/gemini', @body);
exit;
sub header
{
my $dbh = DBI->connect($dsn, '', '', { RaiseError => 1 }) or die $DBI::errstr;
my $tagcount = $dbh->selectrow_array("SELECT count(id) from tags");
my $faqcount = $dbh->selectrow_array("SELECT count(id) from questions");
$dbh->disconnect();
return sprintf('We are currently serving %d FAQs categorized with %d tags!', $faqcount, $tagcount);
}
sub footer
{
return ('', '=> https://git.sr.ht/~rwa/gmnifaq powered by gmnifaq');
}
sub write_response
{
my ($returncode, $meta, @content) = @_;
if (!defined($RC{$returncode})) { die "Unknown response code!"; }
printf("%d %s\r\n", $RC{$returncode}, ($meta eq '') ? $returncode : $meta);
foreach (@content)
{
print("$_\r\n");
}
exit;
}

105
tags.pl

@ -0,0 +1,105 @@
#!/usr/bin/perl
# Copyright René Wagner 2020
# licenced under BSD 3-Clause licence
# https://git.sr.ht/~rwa/gmni-perl-cgi-demo
use strict;
use DBI;
#use URI::Encode qw(uri_encode uri_decode);
# define return codes
our %RC = (
'INPUT', 10,
'SENSITIVE_INPUT', 11,
'SUCCESS', 20,
'TEMPORARY_REDIRECT', 30,
'PERMANENT_REDIRECT', 31,
'TEMPORARY_FAILURE', 40,
'SERVER_UNAVAILABLE', 41,
'CGI_ERROR', 42,
'PROXY_ERROR', 43,
'SLOW_DOWN', 44,
'PERMANENT_FAILURE', 50,
'NOT_FOUND', 51,
'GONE', 52,
'PROXY_REQUEST_REFUSE', 53,
'BAD_REQUEST', 59,
'CLIENT_CERT_REQUIRED', 60,
'CERT_NOT_AUTHORISED', 61,
'CERT_NOT_VALID', 62
);
my $sitename;
my $siteintro;
my $dsn = "DBI:SQLite:dbname=data/data.sqlite";
# enable UTF-8 mode for everything
use utf8;
binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';
if (!defined($ENV{'SERVER_PROTOCOL'}) || $ENV{'SERVER_PROTOCOL'} ne 'GEMINI')
{
write_response('CGI_ERROR', 'CGI execution error', undef);
}
if ( -f './gmnifaq.conf' ) { do './gmnifaq.conf'; }
if ( !-f 'data/data.sqlite' ) { write_response('PERMANENT_FAILURE', 'Permanent failure', undef) };
my @body = ();
push @body, '# Welcome to '. $sitename;
push @body, '';
push @body, 'Select a tag to browse the questions associated with this tag.';
push @body, '';
push @body, '## Tags';
push @body, '';
push @body, tags();
push @body, footer();
write_response('SUCCESS', 'text/gemini', @body);
exit;
sub tags
{
my $dbh = DBI->connect($dsn, '', '', { RaiseError => 1 }) or die $DBI::errstr;
my @tags;
my $stmt = $dbh->prepare('SELECT name, count(t_id) FROM tags LEFT JOIN tags_questions ON tags_questions.t_id = tags.id GROUP BY t_id');
$stmt->execute();
my $rows = $stmt->fetchall_arrayref;
$dbh->disconnect();
if ( !scalar @$rows ) {
push @body, 'No tags found!';
}
else {
foreach (@$rows)
{
push @tags, sprintf("=> tags.pl?%s %s (%d entrys)", @$_[0], @$_[0], @$_[1]);
}
}
return @tags;
}
sub footer
{
return ('', '=> index.pl [Home]', '=> https://git.sr.ht/~rwa/gmnifaq powered by gmnifaq');
}
sub write_response
{
my ($returncode, $meta, @content) = @_;
if (!defined($RC{$returncode})) { die "Unknown response code!"; }
printf("%d %s\r\n", $RC{$returncode}, ($meta eq '') ? $returncode : $meta);
foreach (@content)
{
print("$_\r\n");
}
exit;
}
Loading…
Cancel
Save