diff --git a/lib/Explain/Controller.pm b/lib/Explain/Controller.pm index efbcc36..828a1cd 100755 --- a/lib/Explain/Controller.pm +++ b/lib/Explain/Controller.pm @@ -17,7 +17,7 @@ sub index { return $self->render unless $plan; # request entity too large - return $self->render( message => 'Your plan is too long.', status => 413 ) + return $self->render( message => 'Your plan is too long.', status => 413 ) if 10_000_000 < length $plan; # public @@ -26,6 +26,11 @@ sub index { # anonymization my $is_anon = $self->req->param( 'is_anon' ) ? 1 : 0; + # plan title + my $title = $self->req->param( 'title' ); + $title = '' unless defined $title; + $title = '' if 'Optional title' eq $title; + # try eval { @@ -54,10 +59,12 @@ sub index { eval { # send mail - $self->send_mail( { - subject => q|Can't create explain from...|, - msg => $plan - } ); + $self->send_mail( + { + subject => q|Can't create explain from...|, + msg => $plan + } + ); }; # leave... @@ -65,7 +72,7 @@ sub index { } # save to database - my $id = $self->database->save_with_random_name( $plan, $is_public, $is_anon, ); + my $id = $self->database->save_with_random_name( $title, $plan, $is_public, $is_anon, ); # redirect to /show/:id return $self->redirect_to( 'show', id => $id ); @@ -75,14 +82,13 @@ sub show { my $self = shift; # value of "/:id" param - my $id = defined $self->stash->{ id } - ? $self->stash->{ id } : ''; + my $id = defined $self->stash->{ id } ? $self->stash->{ id } : ''; # missing or invalid return $self->redirect_to( 'new-explain' ) unless $id =~ m{\A[a-zA-Z0-9]+\z}; # get plan source from database - my $plan = $self->database->get_plan( $id ); + my ( $plan, $title ) = $self->database->get_plan( $id ); # not found in database return $self->redirect_to( 'new-explain', status => 404 ) unless $plan; @@ -105,8 +111,9 @@ sub show { return $self->redirect_to( 'new-explain' ); } - # put explain to stash + # put explain and title to stash $self->stash->{ explain } = $explain; + $self->stash->{ title } = $title; # render will be called automatically return; @@ -138,19 +145,18 @@ sub contact { unless Email::Valid->address( $self->req->param( 'email' ) || '' ); # send - $self->send_mail( { - msg => sprintf( - "\nMessage from: %s <%s>" . - "\nPosted from: %s with %s" . - "\n****************************************\n\n" . - "%s", - $self->req->param( 'name' ) || '', - $self->req->param( 'email' ), - $self->tx->remote_address, - $self->req->headers->user_agent, - $self->req->param( 'message' ) - ) - } ); + $self->send_mail( + { + msg => sprintf( + "\nMessage from: %s <%s>" . "\nPosted from: %s with %s" . "\n****************************************\n\n" . "%s", + $self->req->param( 'name' ) || '', + $self->req->param( 'email' ), + $self->tx->remote_address, + $self->req->headers->user_agent, + $self->req->param( 'message' ) + ) + } + ); # mail sent message $self->flash( message => 'Mail sent' ); @@ -160,6 +166,7 @@ sub contact { } sub help { + # direct to template return ( shift )->render; } diff --git a/lib/Explain/Plugin/Database.pm b/lib/Explain/Plugin/Database.pm index 2021e8f..43c111d 100755 --- a/lib/Explain/Plugin/Database.pm +++ b/lib/Explain/Plugin/Database.pm @@ -66,13 +66,13 @@ sub register { } sub save_with_random_name { - my ( $self, $content, $is_public, $is_anon ) = @_; + my ( $self, $title, $content, $is_public, $is_anon ) = @_; # create statement handler - my $sth = $self->dbh->prepare( 'SELECT register_plan(?, ?, ?)' ); + my $sth = $self->dbh->prepare( 'SELECT register_plan(?, ?, ?, ?)' ); # execute - $sth->execute( $content, $is_public, $is_anon ); + $sth->execute( $title, $content, $is_public, $is_anon ); # register_plan returns plan id my @row = $sth->fetchrow_array; @@ -90,7 +90,7 @@ sub get_plan { my ( $self, $plan_id ) = @_; # create statement handler - my $sth = $self->dbh->prepare( 'SELECT plan FROM plans WHERE id = ?' ); + my $sth = $self->dbh->prepare( 'SELECT plan, title FROM plans WHERE id = ?' ); # execute $sth->execute( $plan_id ); @@ -102,7 +102,7 @@ sub get_plan { $sth->finish; # return plan - return $row[ 0 ]; + return @row; } sub get_public_list { diff --git a/sql/create.sql b/sql/create.sql old mode 100755 new mode 100644 index 5238ea9..44adfe9 --- a/sql/create.sql +++ b/sql/create.sql @@ -1,32 +1,36 @@ -\connect template1 postgres +-- +-- PostgreSQL database dump +-- -\set ON_ERROR_STOP OFF +SET statement_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SET check_function_bodies = false; +SET client_min_messages = warning; -DROP DATABASE "explain"; +-- +-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: - +-- -DROP USER "explain"; +CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; -\set ON_ERROR_STOP ON -CREATE USER "explain" WITH password 'explain'; +-- +-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: - +-- -CREATE DATABASE "explain" WITH encoding 'utf8' owner "explain"; +COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; -\connect "explain" postgres -CREATE procedural LANGUAGE plpgsql; +SET search_path = public, pg_catalog; -\connect "explain" "explain" +-- +-- Name: get_random_string(integer); Type: FUNCTION; Schema: public; Owner: - +-- --- plan -CREATE TABLE plans ( - id TEXT PRIMARY KEY, - plan TEXT NOT NULL, - entered_on timestamptz NOT NULL DEFAULT now( ), - is_public bool NOT NULL DEFAULT 'true' -); - -CREATE OR REPLACE FUNCTION get_random_string( string_length INT4 ) RETURNS TEXT AS $$ +CREATE FUNCTION get_random_string(string_length integer) RETURNS text + LANGUAGE plpgsql + AS $$ DECLARE possible_chars TEXT = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; output TEXT = ''; @@ -34,34 +38,167 @@ DECLARE pos INT4; BEGIN FOR i IN 1..string_length LOOP - pos := 1 + cast( random( ) * ( length( possible_chars ) - 1 ) AS INT4 ); - output := output || substr( possible_chars, pos, 1 ); - END LOOP; + pos := 1 + cast( random() * ( length(possible_chars) - 1) as INT4 ); + output := output || substr(possible_chars, pos, 1); + END LOOP; RETURN output; END; -$$ LANGUAGE plpgsql; +$$; -CREATE OR REPLACE FUNCTION register_plan( in_plan TEXT, in_is_public BOOL ) RETURNS TEXT AS $$ + +-- +-- Name: register_plan(text, boolean); Type: FUNCTION; Schema: public; Owner: - +-- + +CREATE FUNCTION register_plan(in_plan text, in_is_public boolean) RETURNS text + LANGUAGE plpgsql + AS $$ DECLARE - use_hash_length INT4 := 2; - use_hash TEXT; + use_hash_length int4 := 2; + use_hash text; BEGIN LOOP - use_hash := get_random_string( use_hash_length ); - + use_hash := get_random_string(use_hash_length); BEGIN - INSERT INTO plans ( id, plan, is_public, entered_on ) VALUES ( use_hash, in_plan, in_is_public, now( ) ); + INSERT INTO plans (id, plan, is_public, entered_on) values (use_hash, in_plan, in_is_public, now()); RETURN use_hash; - EXCEPTION when unique_violation THEN + EXCEPTION WHEN unique_violation THEN -- do nothing END; - use_hash_length := use_hash_length + 1; - IF use_hash_length >= 30 THEN - raise EXCEPTION 'Random string of length == 30 requested. Something is wrong.'; + raise exception 'Random string of length == 30 requested. something''s wrong.'; END IF; - END LOOP; END; -$$ LANGUAGE plpgsql; +$$; + + +-- +-- Name: register_plan(text, boolean, boolean); Type: FUNCTION; Schema: public; Owner: - +-- + +CREATE FUNCTION register_plan(in_plan text, in_is_public boolean, in_is_anonymized boolean) RETURNS text + LANGUAGE plpgsql + AS $$ +DECLARE + use_hash_length int4 := 2; + use_hash text; +BEGIN + LOOP + use_hash := get_random_string(use_hash_length); + BEGIN + INSERT INTO plans (id, plan, is_public, entered_on, is_anonymized) values (use_hash, in_plan, in_is_public, now(), in_is_anonymized); + RETURN use_hash; + EXCEPTION WHEN unique_violation THEN + -- do nothing + END; + use_hash_length := use_hash_length + 1; + IF use_hash_length >= 30 THEN + raise exception 'Random string of length == 30 requested. something''s wrong.'; + END IF; + END LOOP; +END; +$$; + + +-- +-- Name: register_plan(text, text, boolean, boolean); Type: FUNCTION; Schema: public; Owner: - +-- + +CREATE FUNCTION register_plan(in_title text, in_plan text, in_is_public boolean, in_is_anonymized boolean) RETURNS text + LANGUAGE plpgsql + AS $$ +DECLARE + use_hash_length int4 := 2; + use_hash text; +BEGIN + LOOP + use_hash := get_random_string(use_hash_length); + BEGIN + INSERT INTO plans (id, title, plan, is_public, entered_on, is_anonymized) values (use_hash, in_title, in_plan, in_is_public, now(), in_is_anonymized); + RETURN use_hash; + EXCEPTION WHEN unique_violation THEN + -- do nothing + END; + use_hash_length := use_hash_length + 1; + IF use_hash_length >= 30 THEN + raise exception 'Random string of length == 30 requested. something''s wrong.'; + END IF; + END LOOP; +END; +$$; + + +SET default_tablespace = ''; + +SET default_with_oids = false; + +-- +-- Name: another; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE another ( + i integer +); + + +-- +-- Name: plans; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE plans ( + id text NOT NULL, + plan text NOT NULL, + entered_on timestamp with time zone DEFAULT now() NOT NULL, + is_public boolean DEFAULT true NOT NULL, + is_anonymized boolean DEFAULT false NOT NULL, + title text +); + + +-- +-- Name: z; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE z ( + i integer NOT NULL, + j integer NOT NULL +); + + +-- +-- Name: plans_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY plans + ADD CONSTRAINT plans_pkey PRIMARY KEY (id); + + +-- +-- Name: z_i_key; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY z + ADD CONSTRAINT z_i_key UNIQUE (i); + + +-- +-- Name: z_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY z + ADD CONSTRAINT z_pkey PRIMARY KEY (j, i); + + +-- +-- Name: r; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE UNIQUE INDEX r ON z USING btree (j); + + +-- +-- PostgreSQL database dump complete +-- + diff --git a/templates/controller/index.html.ep b/templates/controller/index.html.ep index 62f0723..a595486 100755 --- a/templates/controller/index.html.ep +++ b/templates/controller/index.html.ep @@ -15,6 +15,8 @@